Skip to content

Introduction to the servant haskell library for the Haskell meetup, 2016 January 13, San Francisco

License

Notifications You must be signed in to change notification settings

rubenmoor/sf-servant-tutorial

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

The code below can be found in its final form in this repository on github:

[email protected]:rubenmoor/sf-servant-tutorial.git

Initialize new project with stack

$ cd sf-servant-tutorial
$ stack new sf-servant-tutorial --bare new-template --resolver lts-4.1
$ stack build # just for fun
$ stack exec sf-servant-tutorial-exe

Edit files to run a web server

-- app/Main.hs

module Main where

import Lib

main :: IO ()
main = startServer

-- src/Lib.hs

{-# LANGUAGE OverloadedStrings #-}

module Lib
    ( startServer
    ) where

import           Network.HTTP.Types       (status200)
import           Network.Wai              (Request, Response, responseBuilder)
import qualified Network.Wai.Handler.Warp as Warp

startServer :: IO ()
startServer = Warp.run 3000 app

app :: Request -> (Response -> t) -> t
app _ respond = respond $ responseBuilder
                          status200
                          [("Content-Type", "text/plain")]
                          "hello world"


-- sf-servant-tutorial.cabal

-- ...
library
  hs-source-dirs:      src
  exposed-modules:     Lib
  build-depends:       base >= 4.7 && < 5
                     , http-types
                     , wai
                     , warp
  default-language:    Haskell2010
-- ...

Check if everythings works as expected

$ stack exec sf-servant-tutorial-exe

Inside a browser, go to

http://localhost:3000/

Now add servant to serve an API. Starting with required packages:

-- sf-servant-tutorial.cabal

-- ...
library
  hs-source-dirs:      src
  exposed-modules:     Lib
  build-depends:       base >= 4.7 && < 5
                     , aeson
                     , servant-server
                     , transformers
                     , wai
                     , warp
  default-language:    Haskell2010
-- ...

-- src/Lib.hs

Compiler extensions. Servant uses DataKinds for compile-time check of the content-types. DeriveGeneric for generic JSON instance. Servant uses TypeOperators to allow operator syntax in type definitions.

{-# LANGUAGE DataKinds         #-}
{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators     #-}

module Lib
    ( startServer
    ) where

import           Control.Monad.IO.Class   (liftIO)
import           Data.Aeson               (ToJSON)
import           GHC.Generics             (Generic)

import           Network.Wai              (Application)
import qualified Network.Wai.Handler.Warp as Warp
import           Servant                  ((:>), Get, JSON, Proxy (Proxy),
                                           Server, serve)

Now serving an app :: Application, taken care of by servant.

startServer :: IO ()
startServer = Warp.run 3000 app

Mocking some data entries.

-- schema

data User = User
  { userName  :: String
  , userEmail :: String
  } deriving (Generic)

-- a ghc bug generates a warning here
instance ToJSON User

-- instad of a database

alice :: User
alice = User "Alice" "[email protected]"

bob :: User
bob = User "Robert" "[email protected]"

-- imagine a database action
getUsers :: IO [User]
getUsers = pure [alice, bob]

Now build the actual "servant application"

-- the app

app :: Application
app = serve api server

-- the API, or the routes

type Api = "users" :> Get '[JSON] [User]

-- Server Api == EitherT ServantErr IO [User]
server :: Server Api
server = liftIO getUsers

api :: Proxy Api
api = Proxy

Why is Proxy needed here? Further information can be found in this stackoverflow question.

About

Introduction to the servant haskell library for the Haskell meetup, 2016 January 13, San Francisco

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages