Web Development
49.1 Servant: APIs as Types
From the same API type, Servant can derive clients (servant-client), OpenAPI/Swagger docs (servant-openapi3), and type-safe links. The handler types are checked against the API.
{-# LANGUAGE DataKinds, TypeOperators, DeriveGeneric, DeriveAnyClass #-}
import Servant
import Network.Wai.Handler.Warp (run)
import Data.Aeson (ToJSON, FromJSON)
import GHC.Generics (Generic)
import Data.IORef
import Control.Monad.IO.Class (liftIO)
data Todo = Todo {todoId :: Int, title :: String, done :: Bool}
deriving (Show, Generic, ToJSON, FromJSON)
type TodoAPI =
"todos" :> Get '[JSON] [Todo]
:<|> "todos" :> Capture "id" Int :> Get '[JSON] Todo
:<|> "todos" :> ReqBody '[JSON] Todo :> Post '[JSON] Todo
:<|> "health" :> Get '[PlainText] String
server :: IORef [Todo] -> Server TodoAPI
server ref = listTodos :<|> getTodo :<|> createTodo :<|> health
where
listTodos = liftIO (readIORef ref)
getTodo i = do
todos <- liftIO (readIORef ref)
case filter ((== i) . todoId) todos of
(t : _) -> pure t
[] -> throwError err404
createTodo t = liftIO (modifyIORef' ref (t :)) >> pure t
health = pure "ok"
main :: IO ()
main = do
ref <- newIORef [Todo 1 "Learn Servant" False]
putStrLn "Listening on :8080"
run 8080 (serve (Proxy :: Proxy TodoAPI) (server ref))49.2 Other Web Frameworks
Minimal, Sinatra-like (get "/hello/:name" $ do...) Full-stack, type-safe routes, Shakespearean templates, persistent integration
Batteries-included, Rails-like, live reload, PostgreSQL-centric
Type-level API specification (see above) Spock, Twain, Okapi
The common foundation (interface + fast HTTP server) Miso, Reflex-FRP, Obelisk
Frontend / full-stack functional reactive programming (GHCJS / GHC's JS & WASM backends)
HTTP clients: http-client, req, wreq, http-conduit. HTML: lucid, blaze-html. Logging: katip, co-log, monad-logger. Configuration: dhall, envy, yaml.
{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty
main :: IO ()
main = scotty 3000 $ do
get "/" $ text "Hello from Scotty"
get "/hello/:name" $ do
name <- pathParam "name" -- older Scotty versions use `param`
html ("<h1>Hello, " <> name <> "!</h1>")