Automatically derive Elm functions to query servant webservices.

Version on this page:
LTS Haskell 12.22:
Stackage Nightly 2018-12-14:
Latest on Hackage:

See all snapshots servant-elm appears in

BSD3 licensed by Matt Bray
Maintained by

Module documentation for

There are no documented modules for this package.

Servant Elm

Build Status

Generate Elm functions to query your Servant API!

Elm type generation coutesy of krisajenkins/elm-export.


Servant Elm is available on Hackage.


First, some language pragmas and imports.

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

import           Elm          (Spec (Spec), specsToDir, toElmDecoderSource,
import           GHC.Generics (Generic)
import           Servant.API  ((:>), Capture, Get, JSON)
import           Servant.Elm  (ElmType, Proxy (Proxy), defElmImports,

We have some Haskell-defined types and our Servant API.

data Book = Book
    { name :: String
    } deriving (Generic)

instance ElmType Book

type BooksApi = "books" :> Capture "bookId" Int :> Get '[JSON] Book

Now we can generate Elm functions to query the API:

spec :: Spec
spec = Spec ["Generated", "MyApi"]
             : toElmTypeSource    (Proxy :: Proxy Book)
             : toElmDecoderSource (Proxy :: Proxy Book)
             : generateElmForAPI  (Proxy :: Proxy BooksApi))

main :: IO ()
main = specsToDir [spec] "my-elm-dir"

Let’s save this as example.hs and run it:

$ stack runghc example.hs
Writing: my-elm-dir/Generated/MyApi.elm

Here’s what was generated:

module Generated.MyApi exposing (..)

import Json.Decode exposing (..)
import Json.Decode.Pipeline exposing (..)
import Json.Encode
import Http
import String

type alias Book =
    { name : String

decodeBook : Decoder Book
decodeBook =
    decode Book
        |> required "name" string

getBooksByBookId : Int -> Http.Request (Book)
getBooksByBookId capture_bookId =
        { method =
        , headers =
        , url =
            String.join "/"
                [ ""
                , "books"
                , capture_bookId |> toString |> Http.encodeUri
        , body =
        , expect =
            Http.expectJson decodeBook
        , timeout =
        , withCredentials =

See examples for a complete usage example, or take a look at mattjbray/servant-elm-example-app for an example project using this library.


$ git clone
$ cd servant-elm
$ stack test
$ stack test --flag servant-elm:integration

To build all examples:

$ make examples

To run an example:

$ cd examples/e2e-tests
$ elm-reactor
# Open http://localhost:8000/elm/Main.elm


  • Fix generation for APIs with response headers.
  • Support Servant’s Optional and Required modifiers for Headers and QueryParams (Header arguments are now Maybes by default). (phaazon) (#31)
  • Filter out forbidden Cookie header. (xilnocas) (#37)

  • Remove hyphens from generated function names. (servant-foreign-0.10 no longer does this for us.)

  • Allow passing the base URL dynamically in Elm. (#20)
  • Don’t use toString on Text parameters. (domenkozar) (#23, #24)
  • Fix query parameter generation. (domenkozar) (#25)

  • Prefix generated function arguments to ensure valid Elm identifiers (#21)
  • Put integration tests behind a Cabal flag. (#22)

  • Update for Elm 0.18 and the new elm-lang/http library.
  • Generated Elm functions now return an Http.Request value.

  • Use Text throughout the API.
  • We no longer auto-generate Elm sources for the types, encoders and decoders used in your API - you must now use elm-export’s toElmTypeSource functions explicitly. See the tests and examples for usage.
  • Allow setting options to pass to elm-export.
  • Update to servant-0.8 (purcell).
  • Basic support for custom headers.
  • Fix: String query params were being wrapped in double-quotes.
  • Test: verify that the generated code can be compiled by Elm (soenkehahn)

  • Fix for API endpoints that return Unit (kantp)

  • Convenience re-exports from Elm and Data.Proxy.
  • Add Haddoc documentation.


  • Initial release.
comments powered byDisqus