Skip to content

Instantly share code, notes, and snippets.

Created June 26, 2015 18:07
Show Gist options
  • Save anonymous/a99bc6b36ac2db64878e to your computer and use it in GitHub Desktop.
Save anonymous/a99bc6b36ac2db64878e to your computer and use it in GitHub Desktop.
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE DeriveGeneric #-}
module Main where
import Network.Wai.Handler.Warp (run)
import System.Environment (lookupEnv)
import Database.Persist.Sql (runSqlPool)
import Control.Monad.Reader (ReaderT, runReaderT, lift)
import Control.Monad.Trans.Either (EitherT, left)
import Network.Wai (Application)
import Servant
import qualified Servant.Utils.StaticFiles as S
import Database.Persist.Sqlite (ConnectionPool, createSqlitePool)
import Data.Aeson (ToJSON, FromJSON)
import GHC.Generics (Generic)
data Config = Config { getPool :: ConnectionPool , getEnv :: Environment }
defaultConfig :: Config
defaultConfig = Config { getPool = undefined , getEnv = Development }
data Environment = Development | Test | Production deriving (Eq, Show, Read)
data Person = Person { name :: String , email :: String } deriving (Eq, Show, Generic)
instance ToJSON Person
instance FromJSON Person
type PersonAPI =
"users" :> Capture "name" String :> Get '[JSON] Person
:<|> "static" :> Raw
type AppM = ReaderT Config (EitherT ServantErr IO)
userAPI :: Proxy PersonAPI
userAPI = Proxy
app :: Config -> Application
app cfg = serve userAPI (readerServer cfg)
readerServer :: Config -> Server PersonAPI
readerServer cfg = enter (readerToEither cfg) server
readerToEither :: Config -> AppM :~> EitherT ServantErr IO
readerToEither cfg = Nat $ \x -> runReaderT x cfg
server :: ServerT PersonAPI AppM
server = singlePerson :<|> S.serveDirectory "/static"
singlePerson :: String -> AppM Person
singlePerson str = do
let person = Person { name = "Joe", email = "joe@example.com" }
return person
main :: IO ()
main = do
let cfg = defaultConfig
run 8081 $ app cfg
@alpmestan
Copy link

This should work just fine (basically keep the non Raw endpoints in a type, use enter on it, and then stick the file serving handler next to the result of enter):

type PersonAPI = 
    "users" :> Capture "name" String :> Get '[JSON] Person
   -- NEW: removed Raw from here

-- NEW
type WholeAPI = PersonAPI :<|> Raw

type AppM = ReaderT Config (EitherT ServantErr IO)

userAPI :: Proxy PersonAPI
userAPI = Proxy

-- NEW
wholeAPI :: Proxy WholeAPI
wholeAPI = Proxy

-- changed 'userAPI' to 'wholeAPI'
app :: Config -> Application
app cfg = serve wholeAPI (readerServer cfg)

readerServer :: Config -> Server WholeAPI
readerServer cfg = enter (readerToEither cfg) server
                        :<|> S.serveDirectory "/static" -- NEW

readerToEither :: Config -> AppM :~> EitherT ServantErr IO
readerToEither cfg = Nat $ \x -> runReaderT x cfg

server :: ServerT PersonAPI AppM
server = singlePerson

singlePerson :: String -> AppM Person
singlePerson str = do
    let person = Person { name = "Joe", email = "joe@example.com" }
    return person

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment