<commit_before>---
title: ARoW.info Blog -- Servant Intro
headingBackgroundImage: ../img/post-bg.jpg
headingDivClass: post-heading
heading: Here is a title
subHeading: Problems look mighty small from 150 miles up
postedBy: <NAME>
---

Servant is a really nice library for building REST APIs in Haskell.  However,
it uses advanced GHC features which may not be familiar to some Haskell
programmers.  In this article, I explain type-level strings, type-level lists,
type-level operators, and type families.  Finally, I use code from
servant-server to explain how these features are used in practice.

Servant Example
---------------

Here is a simple example of using servant-server.  We will refer to this code
throughout this article.

```
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}

module Main where

import Control.Monad.Trans.Either (EitherT)
import Network.Wai (Application)
import Network.Wai.Handler.Warp (run)
import Network.Wai.Middleware.RequestLogger (logStdoutDev)
import Servant
    ( (:>), (:<|>)((:<|>)), Get, JSON, Proxy(..), ServantErr, ServerT, serve )

type MyAPI = "dogs" :> Get '[JSON] [Int]
        :<|> "cats" :> Get '[JSON] [String]

app :: Application
app = serve (Proxy :: Proxy MyAPI) myAPI

myAPI :: ServerT MyAPI (EitherT ServantErr IO)
myAPI = dogNums :<|> cats

dogNums :: EitherT ServantErr IO [Int]
dogNums = return [1,2,3,4]

cats :: EitherT ServantErr IO [String]
cats = return ["long-haired", "short-haired"]

main :: IO ()
main = run 32323 $ logStdoutDev app
```

This example project can be found at the gist
https://gist.github.com/cdepillabout/c2b8b1807e1f571fdb45#file-example-hs

The following steps can be used to download and run the code.  The stack build
tool is used.

```
$ git clone https://gist.github.com/c2b8b1807e1f571fdb45.git
$ mv c2b8b1807e1f571fdb45 small-servant-example
$ cd small-servant-example
$ stack build
$ stack exec servant-notes
```

This runs a Warp server on port 32323.  With the server running, you can use
curl to test the API.

```
$ curl http://localhost:32323/dogs
[1,2,3,4]
$ curl http://localhost:32323/cats
["long-haired","short-haired"]
$
```

You can also open the code in ghci.

```
$ stack ghci
ghci> :load example.hs
ghci> :info app
app :: Application      -- Defined at example.hs:17:1
ghci>
```

Type-Level Strings
------------------

Recent versions of GHC support [type-level
strings](https://downloads.haskell.org/~ghc/7.10.1/docs/html/users_guide/type-level-literals.html).
What's a type-level string?  Well, let's play around with it in the REPL.

First, we need to enable the DataKinds language extension.<commit_msg>Formatted more of blog post.<commit_after>---
title: ARoW.info Blog -- Type-level Things, Type Families, and Servant
headingBackgroundImage: ../img/post-bg.jpg
headingDivClass: post-heading
heading: Type-level Things, Type Families, and Servant
subHeading: A look at advanced GHC features used in Servant
postedBy: <NAME>
---

Servant is a really nice library for building REST APIs in Haskell.  However,
it uses advanced GHC features which may not be familiar to some Haskell
programmers.  In this article, I explain type-level strings, type-level lists,
type-level operators, and type families.  Finally, I use code from
servant-server to explain how these features are used in practice.

## Servant Example

Here is a simple example of using servant-server.  We will refer to this code
throughout the article.

```haskell
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}

module Main where

import Control.Monad.Trans.Either (EitherT)
import Network.Wai (Application)
import Network.Wai.Handler.Warp (run)
import Network.Wai.Middleware.RequestLogger (logStdoutDev)
import Servant
    ( (:>), (:<|>)((:<|>)), Get, JSON, Proxy(..), ServantErr, ServerT, serve )

-- | A representation of our REST API at the type level.
--
-- This defines two routes:
--   * /dogs -- Responds to HTTP GET with a list of integers in JSON format.
--   * /cats -- Responds to HTTP GET with a list of Strings in JSON format.
type MyAPI = "dogs" :> Get '[JSON] [Int]
        :<|> "cats" :> Get '[JSON] [String]

-- | A Warp 'Application' that will serve our API.
app :: Application
app = serve (Proxy :: Proxy MyAPI) myAPI

-- | Our entire API.  You can see that it is a combination of the 'dogNums'
-- handler and the 'cats' handler.
myAPI :: ServerT MyAPI (EitherT ServantErr IO)
myAPI = dogNums :<|> cats

-- | A handler for the /dogs route.  It just returns a list of the integers
-- one to four.
dogNums :: EitherT ServantErr IO [Int]
dogNums = return [1,2,3,4]

-- | A handler for the /cats route.
cats :: EitherT ServantErr IO [String]
cats = return ["long-haired", "short-haired"]

-- | Run our 'app' as a Warp 'Application'.
main :: IO ()
main = run 32323 $ logStdoutDev app
```

The example project can be found [on
Github](https://gist.github.com/cdepillabout/c2b8b1807e1f571fdb45#file-example-hs).
The comments in the code should give you a good idea of what is going on, but
if you would like a better introduction, the [Servant
tutorial](http://haskell-servant.github.io/tutorial/) is very good.

The following steps can be used to download and run the code.  The
[stack](https://github.com/commercialhaskell/stack) build tool is used.

```bash
$ git clone https://gist.github.com/c2b8b1807e1f571fdb45.git
$ mv c2b8b1807e1f571fdb45 small-servant-example
$ cd small-servant-example
$ stack build
$ stack exec servant-notes
```

This runs a Warp server on port 32323.  With the server running, you can use
curl to test the API.

```
$ curl http://localhost:32323/dogs
[1,2,3,4]
$ curl http://localhost:32323/cats
["long-haired","short-haired"]
$
```

You can also open the code in ghci.

```
$ stack ghci
ghci> :load example.hs
ghci> :info app
app :: Application      -- Defined at example.hs:17:1
ghci>
```

## Type-Level Strings

Recent versions of GHC support [type-level
strings](https://downloads.haskell.org/~ghc/7.10.1/docs/html/users_guide/type-level-literals.html).
What's a type-level string?  Well, let's play around with it in the REPL.

First, we need to enable the DataKinds language extension.
{'fraction_non_alphanumeric': 0.12118740825313978, 'fraction_numerical': 0.02365030174522916, 'mean_word_length': 3.917401764234162, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 25, 'https://': 7, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4438573', 'n_tokens_mistral': 2151, 'n_tokens_neox': 1987, 'n_words': 735}