# Servant Elm
[](https://travis-ci.org/mattjbray/servant-elm)
Generate Elm functions to query your Servant API!
Elm type generation coutesy of [krisajenkins/elm-export](https://github.com/krisajenkins/elm-export).
## Installation
Until `elm-export` and `servant >= 0.5` are released, `servant-elm` requires
stack. Add this to your `stack.yaml` file:
```yaml
...
packages:
...
- location:
git: https://github.com/haskell-servant/servant.git
commit: 761443fffecbe83aa408d5f705dd0a8dade08af9
subdirs:
- servant
- servant-foreign
- servant-server
extra-dep: True
- location:
git: https://www.github.com/mattjbray/elm-export
commit: a8a5b61798fbb04e081f5c83cab76ceaabc5ba13
extra-dep: True
- location:
git: https://www.github.com/mattjbray/servant-elm
commit: 749e09ed9d623284b3b90d1ae1ccba7ae79ad381
extra-dep: True
...
```
## Example
Let's get some language pragmas and imports out of the way.
```haskell
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeOperators #-}
import GHC.Generics (Generic)
import Servant.API ((:>), Capture, Get, JSON)
import Servant.Elm (Proxy (Proxy), Spec (Spec), ToElmType,
defElmImports, generateElmForAPI, specsToDir,
specsToDir)
```
We have some Haskell-defined types and our Servant API.
```haskell
data Book = Book
{ name :: String
} deriving (Generic)
instance ToElmType Book
type BooksApi = "books" :> Capture "bookId" Int :> Get '[JSON] Book
```
Now we can generate Elm functions to query the API:
```haskell
spec :: Spec
spec = Spec ["Generated", "MyApi"]
(defElmImports
: 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:
```elm
module Generated.MyApi where
import Json.Decode exposing ((:=))
import Json.Decode.Extra exposing ((|:))
import Json.Encode
import Http
import String
import Task
type alias Book =
{ name : String
}
decodeBook : Json.Decode.Decoder Book
decodeBook =
Json.Decode.succeed Book
|: ("name" := Json.Decode.string)
getBooksBy : Int -> Task.Task Http.Error (Book)
getBooksBy bookId =
let
request =
{ verb =
"GET"
, headers =
[("Content-Type", "application/json")]
, url =
"/" ++ "books"
++ "/" ++ (bookId |> toString |> Http.uriEncode)
, body =
Http.empty
}
in
Http.fromJson
decodeBook
(Http.send Http.defaultSettings request)
```
See [`examples`](examples) for a complete usage example, or take a look at
[mattjbray/servant-elm-example-app](https://github.com/mattjbray/servant-elm-example-app)
for an example project using this library.
## Development
```
$ git clone https://github.com/mattjbray/servant-elm.git
$ cd servant-elm
$ stack build
$ stack test
```
## TODO
Servant API coverage:
* MatrixFlag / MatrixParam / MatrixParams
* Header (request)
* Headers (response)
* Delete / Patch / Put / Raw
* Vault / RemoteHost / IsSecure
Other:
* Encode captures and query params?
* Option to not use elm-export: generate functions that take a decoder and
String arguments.