packages feed

servant-elm-0.1.0.2: README.md

# Servant Elm

[![Build Status](https://travis-ci.org/mattjbray/servant-elm.svg?branch=master)](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.