@@ -1,35 +1,12 @@
1−---
2−title: Serving an API
3−toc: true
4−---
1+# Serving an API
52
63Enough chit-chat about type-level combinators and representing an API as a
74type. Can we have a webservice already?
85
9−If you want to follow along with the code and run the examples while you read this guide:
6+## A first example
107
11−``` bash
12−cabal get servant-examples
13−cd servant-examples-<VERSION>
14−cabal sandbox init
15−cabal install --dependencies-only
16−cabal configure && cabal build
17−```
18−
19−This will produce a `tutorial` executable in the
20−`dist/build/tutorial` directory that just runs the example corresponding
21−to the number specified as a command line argument:
22−
23−``` bash
24−$ dist/build/tutorial/tutorial
25−Usage: tutorial N
26− where N is the number of the example you want to run.
27−```
28−
29−A first example
30−===============
31−
32−Equipped with some basic knowledge about the way we represent API, let's now write our first webservice.
8+Equipped with some basic knowledge about the way we represent APIs, let's now
9+write our first webservice.
3310
3411The source for this tutorial section is a literate haskell file, so first we
3512need to have some language extensions and imports:
@@ -41,6 +18,7 @@ need to have some language extensions and imports:
4118{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4219{-# LANGUAGE MultiParamTypeClasses #-}
4320{-# LANGUAGE OverloadedStrings #-}
21+{-# LANGUAGE RankNTypes #-}
4422{-# LANGUAGE ScopedTypeVariables #-}
4523{-# LANGUAGE TypeOperators #-}
4624
@@ -49,15 +27,14 @@ module Server where
4927import Prelude ()
5028import Prelude.Compat
5129
52−import Control.Monad.IO.Class
30+import Control.Monad.Except
5331import Control.Monad.Reader
54−import Control.Monad.Trans.Except
5532import Data.Aeson
5633import Data.Aeson.Types
5734import Data.Attoparsec.ByteString
5835import Data.ByteString (ByteString)
59−import Data.Int
6036import Data.List
37+import Data.Maybe
6138import Data.String.Conversions
6239import Data.Time.Calendar
6340import GHC.Generics
@@ -69,15 +46,18 @@ import Servant
6946import System.Directory
7047import Text.Blaze
7148import Text.Blaze.Html.Renderer.Utf8
49+import Servant.Types.SourceT (source)
7250import qualified Data.Aeson.Parser
7351import qualified Text.Blaze.Html
7452```
7553
76−``` haskell ignore
77−{-# LANGUAGE TypeFamilies #-}
78−```
79−
80−**Important**: the `Servant` module comes from the *servant-server* package, the one that lets us run webservers that implement a particular API type. It reexports all the types from the *servant* package that let you declare API types as well as everything you need to turn your request handlers into a fully-fledged webserver. This means that in your applications, you can just add *servant-server* as a dependency, import `Servant` and not worry about anything else.
54+**Important**: the `Servant` module comes from the **servant-server** package,
55+the one that lets us run webservers that implement a particular API type. It
56+reexports all the types from the **servant** package that let you declare API
57+types as well as everything you need to turn your request handlers into a
58+fully-fledged webserver. This means that in your applications, you can just add
59+**servant-server** as a dependency, import `Servant` and not worry about anything
60+else.
8161
8262We will write a server that will serve the following API.
8363
@@ -116,12 +96,6 @@ users1 =
11696 ]
11797```
11898
119−Let's also write our API type.
120−
121−``` haskell ignore
122−type UserAPI1 = "users" :> Get '[JSON] [User]
123−```
124−
12599We can now take care of writing the actual webservice that will handle requests
126100to such an API. This one will be very simple, being reduced to just a single
127101endpoint. The type of the web application is determined by the API type,
@@ -133,11 +107,11 @@ corresponding API type.
133107The first thing to know about the `Server` type family is that behind the
134108scenes it will drive the routing, letting you focus only on the business
135109logic. The second thing to know is that for each endpoint, your handlers will
136−by default run in the `ExceptT ServantErr IO` monad. This is overridable very
110+by default run in the `Handler` monad. This is overridable very
137111easily, as explained near the end of this guide. Third thing, the type of the
138112value returned in that monad must be the same as the second argument of the
139113HTTP method combinator used for the corresponding endpoint. In our case, it
140−means we must provide a handler of type `ExceptT ServantErr IO [User]`. Well,
114+means we must provide a handler of type `Handler [User]`. Well,
141115we have a monad, let's just `return` our list:
142116
143117``` haskell
@@ -145,7 +119,9 @@ server1 :: Server UserAPI1
145119server1 = return users1
146120```
147121
148−That's it. Now we can turn `server` into an actual webserver using [wai](http://hackage.haskell.org/package/wai) and [warp](http://hackage.haskell.org/package/warp):
122+That's it. Now we can turn `server` into an actual webserver using
123+[wai](http://hackage.haskell.org/package/wai) and
124+[warp](http://hackage.haskell.org/package/warp):
149125
150126``` haskell
151127userAPI :: Proxy UserAPI1
@@ -155,7 +131,7 @@ userAPI = Proxy
155131-- which you can think of as an "abstract" web application,
156132-- not yet a webserver.
157133app1 :: Application
158−app1 = serve userAPI EmptyConfig server1
134+app1 = serve userAPI server1
159135```
160136
161137The `userAPI` bit is, alas, boilerplate (we need it to guide type inference).
@@ -170,9 +146,8 @@ main = run 8081 app1
170146
171147You can put this all into a file or just grab [servant's
172148repo](http://github.com/haskell-servant/servant) and look at the
173−*servant-examples* directory. The code we have just explored is in
174−*tutorial/T1.hs*, runnable with
175−`dist/build/tutorial/tutorial 1`.
149+*doc/tutorial* directory. This code (the source of this web page) is in
150+*doc/tutorial/Server.lhs*.
176151
177152If you run it, you can go to `http://localhost:8081/users` in your browser or
178153query it with curl and you see:
@@ -182,10 +157,10 @@ $ curl http://localhost:8081/users
182157[{"email":"isaac@newton.co.uk","registration_date":"1683-03-01","age":372,"name":"Isaac Newton"},{"email":"ae@mc2.org","registration_date":"1905-12-01","age":136,"name":"Albert Einstein"}]
183158```
184159
185−More endpoints
186−==============
160+## More endpoints
187161
188−What if we want more than one endpoint? Let's add `/albert` and `/isaac` to view the corresponding users encoded in JSON.
162+What if we want more than one endpoint? Let's add `/albert` and `/isaac` to
163+view the corresponding users encoded in JSON.
189164
190165``` haskell
191166type UserAPI2 = "users" :> Get '[JSON] [User]
@@ -208,7 +183,7 @@ users2 = [isaac, albert]
208183
209184Now, just like we separate the various endpoints in `UserAPI` with `:<|>`, we
210185are going to separate the handlers with `:<|>` too! They must be provided in
211−the same order as the one they appear in in the API type.
186+the same order as in the API type.
212187
213188``` haskell
214189server2 :: Server UserAPI2
@@ -217,22 +192,21 @@ server2 = return users2
217192 :<|> return isaac
218193```
219194
220−And that's it! You can run this example with
221−`dist/build/tutorial/tutorial 2` and check out the data available
222−at `/users`, `/albert` and `/isaac`.
195+And that's it! You can run this example in the same way that we showed for
196+`server1` and check out the data available at `/users`, `/albert` and `/isaac`.
223197
224−From combinators to handler arguments
225−=====================================
198+## From combinators to handler arguments
226199
227200Fine, we can write trivial webservices easily, but none of the two above use
228201any "fancy" combinator from servant. Let's address this and use `QueryParam`,
229−`Capture` and `ReqBody` right away. You'll see how each occurence of these
202+`Capture` and `ReqBody` right away. You'll see how each occurrence of these
230203combinators in an endpoint makes the corresponding handler receive an
231204argument of the appropriate type automatically. You don't have to worry about
232205manually looking up URL captures or query string parameters, or
233206decoding/encoding data from/to JSON. Never.
234207
235−We are going to use the following data types and functions to implement a server for `API`.
208+We are going to use the following data types and functions to implement a
209+server for `API`.
236210
237211``` haskell
238212type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
@@ -240,8 +214,8 @@ type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Posit
240214 :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email
241215
242216data Position = Position
243− { x :: Int
244− , y :: Int
217+ { xCoord :: Int
218+ , yCoord :: Int
245219 } deriving Generic
246220
247221instance ToJSON Position
@@ -291,15 +265,15 @@ server3 = position
291265 :<|> hello
292266 :<|> marketing
293267
294− where position :: Int -> Int -> ExceptT ServantErr IO Position
268+ where position :: Int -> Int -> Handler Position
295269 position x y = return (Position x y)
296270
297− hello :: Maybe String -> ExceptT ServantErr IO HelloMessage
271+ hello :: Maybe String -> Handler HelloMessage
298272 hello mname = return . HelloMessage $ case mname of
299273 Nothing -> "Hello, anonymous coward"
300274 Just n -> "Hello, " ++ n
301275
302− marketing :: ClientInfo -> ExceptT ServantErr IO Email
276+ marketing :: ClientInfo -> Handler Email
303277 marketing clientinfo = return (emailForClient clientinfo)
304278```
305279
@@ -314,99 +288,86 @@ parameter might not always be there);
314288
315289 - a `ReqBody contentTypeList a` becomes an argument of type `a`;
316290
317−And that's it. You can see this example in action by running `dist/build/tutorial/tutorial 3`.
291+And that's it. Here's the example in action:
318292
319293``` bash
320294$ curl http://localhost:8081/position/1/2
321−{"x":1,"y":2}
295+{"xCoord":1,"yCoord":2}
322296$ curl http://localhost:8081/hello
323297{"msg":"Hello, anonymous coward"}
324298$ curl http://localhost:8081/hello?name=Alp
325299{"msg":"Hello, Alp"}
326−$ curl -X POST -d '{"name":"Alp Mestanogullari", "email" : "alp@foo.com", "age": 25, "interested_in": ["haskell", "mathematics"]}' -H 'Accept: application/json' -H 'Content-type: application/json' http://localhost:8081/marketing
300+$ curl -X POST -d '{"clientName":"Alp Mestanogullari", "clientEmail" : "alp@foo.com", "clientAge": 25, "clientInterestedIn": ["haskell", "mathematics"]}' -H 'Accept: application/json' -H 'Content-type: application/json' http://localhost:8081/marketing
327301{"subject":"Hey Alp Mestanogullari, we miss you!","body":"Hi Alp Mestanogullari,\n\nSince you've recently turned 25, have you checked out our latest haskell, mathematics products? Give us a visit!","to":"alp@foo.com","from":"great@company.com"}
328302```
329303
330−For reference, here's a list of some combinators from *servant* and for those
331−that get turned into arguments to the handlers, the type of the argument.
304+For reference, here's a list of some combinators from **servant**:
332305
333− > - `Delete`, `Get`, `Patch`, `Post`, `Put`: these do not become arguments. They provide the return type of handlers, which usually is `ExceptT ServantErr IO <something>`.
306+ > - `Delete`, `Get`, `Patch`, `Post`, `Put`: these do not become arguments. They provide the return type of handlers, which usually is `Handler <something>`.
334307 > - `Capture "something" a` becomes an argument of type `a`.
335− > - `QueryParam "something" a`, `MatrixParam "something" a`, `Header "something" a` all become arguments of type `Maybe a`, because there might be no value at all specified by the client for these.
336− > - `QueryFlag "something"` and `MatrixFlag "something"` get turned into arguments of type `Bool`.
337− > - `QueryParams "something" a` and `MatrixParams "something" a` get turned into arguments of type `[a]`.
308+ > - `QueryParam "something" a`, `Header "something" a` all become arguments of type `Maybe a`, because there might be no value at all specified by the client for these.
309+ > - `QueryFlag "something"` gets turned into an argument of type `Bool`.
310+ > - `QueryParams "something" a` gets turned into an argument of type `[a]`.
338311 > - `ReqBody contentTypes a` gets turned into an argument of type `a`.
339312
340−The `FromText`/`ToText` classes
341−===============================
313+## The `FromHttpApiData`/`ToHttpApiData` classes
342314
343−Wait... How does *servant* know how to decode the `Int`s from the URL? Or how
344−to decode a `ClientInfo` value from the request body? This is what this and the
345−following two sections address.
315+Wait... How does **servant** know how to decode the `Int`s from the URL? Or how
316+to decode a `ClientInfo` value from the request body? The following three sections will
317+help us answer these questions.
346318
347319`Capture`s and `QueryParam`s are represented by some textual value in URLs.
348320`Header`s are similarly represented by a pair of a header name and a
349−corresponding (textual) value in the request's "metadata". This is why we
350−decided to provide a pair of typeclasses, `FromText` and `ToText` which just
351−let you say that you can respectively *extract* or *encode* values of some type
352−*from*/*to* text. Here are the definitions:
321+corresponding (textual) value in the request's "metadata". How types are
322+decoded from headers, captures, and query params is expressed in a class
323+`FromHttpApiData` (from the package
324+[**http-api-data**](http://hackage.haskell.org/package/http-api-data)):
353325
354326``` haskell ignore
355−class FromText a where
356− fromText :: Text -> Maybe a
357−
358−class ToText a where
359− toText :: a -> Text
360−```
327+class FromHttpApiData a where
328+ {-# MINIMAL parseUrlPiece | parseQueryParam #-}
329+ -- | Parse URL path piece.
330+ parseUrlPiece :: Text -> Either Text a
331+ parseUrlPiece = parseQueryParam
361332
362−And as long as the type that a `Capture`/`QueryParam`/`Header`/etc will be
363−decoded to provides a `FromText` instance, it will Just Work. *servant*
364−provides a decent number of instances, but here are some examples of defining
365−your own.
333+ -- | Parse HTTP header value.
334+ parseHeader :: ByteString -> Either Text a
335+ parseHeader = parseUrlPiece . decodeUtf8
366336
367−``` haskell
368−-- A typical enumeration
369−data Direction
370− = Up
371− | Down
372− | Left
373− | Right
374−
375−newtype UserId = UserId Int64
337+ -- | Parse query param value.
338+ parseQueryParam :: Text -> Either Text a
339+ parseQueryParam = parseUrlPiece
376340```
377341
378−or writing the instances by hand:
342+As you can see, as long as you provide either `parseUrlPiece` (for `Capture`s)
343+or `parseQueryParam` (for `QueryParam`s), the other methods will be defined in
344+terms of this.
379345
380−``` haskell ignore
381−instance FromText UserId where
382− fromText = fmap UserId fromText
383−
384−instance ToText UserId where
385− toText (UserId i) = toText i
386−```
346+**http-api-data** provides a decent number of instances, helpers for defining new
347+ones, and wonderful documentation.
387348
388349There's not much else to say about these classes. You will need instances for
389−them when using `Capture`, `QueryParam`, `QueryParams`, `MatrixParam`,
390−`MatrixParams` and `Header` with your types. You will need `FromText` instances
391−for server-side request handlers and `ToText` instances only when using
392−*servant-client*, as described in the [section about deriving haskell
393−functions to query an API](/tutorial/client.html).
350+them when using `Capture`, `QueryParam`, `QueryParams`, and `Header` with your
351+types. You will need `FromHttpApiData` instances for server-side request
352+handlers and `ToHttpApiData` instances only when using
353+**servant-client**, as described in the [section about deriving haskell
354+functions to query an API](Client.html).
394355
395−Using content-types with your data types
396−========================================
356+## Using content-types with your data types
397357
398358The same principle was operating when decoding request bodies from JSON, and
399359responses *into* JSON. (JSON is just the running example - you can do this with
400360any content-type.)
401361
402−This section introduces a couple of typeclasses provided by *servant* that make
362+This section introduces a couple of typeclasses provided by **servant** that make
403363all of this work.
404364
405−The truth behind `JSON`
406−-----------------------
365+### The truth behind `JSON`
366+
407367
408−What exactly is `JSON`? Like the 3 other content types provided out of the box
409−by *servant*, it's a really dumb data type.
368+What exactly is `JSON` (the type as used in `Get '[JSON] User`)? Like the 3
369+other content-types provided out of the box by **servant**, it's a really dumb
370+data type.
410371
411372``` haskell ignore
412373data JSON
@@ -416,14 +377,15 @@ data OctetStream
416377```
417378
418379Obviously, this is not all there is to `JSON`, otherwise it would be quite
419−pointless. Like most of the data types in *servant*, `JSON` is mostly there as
380+pointless. Like most of the data types in **servant**, `JSON` is mostly there as
420381a special *symbol* that's associated with encoding (resp. decoding) to (resp.
421382from) the *JSON* format. The way this association is performed can be
422383decomposed into two steps.
423384
424385The first step is to provide a proper
425−[`MediaType`](https://hackage.haskell.org/package/http-media-0.6.2/docs/Network-HTTP-Media.html)
426−representation for `JSON`, or for your own content types. If you look at the
386+`MediaType` (from
387+[**http-media**](https://hackage.haskell.org/package/http-media-0.6.2/docs/Network-HTTP-Media.html))
388+representation for `JSON`, or for your own content-types. If you look at the
427389haddocks from this link, you can see that we just have to specify
428390`application/json` using the appropriate functions. In our case, we can just
429391use `(//) :: ByteString -> ByteString -> MediaType`. The precise way to specify
@@ -439,14 +401,14 @@ instance Accept JSON where
439401```
440402
441403The second step is centered around the `MimeRender` and `MimeUnrender` classes.
442−These classes just let you specify a way to respectively encode and decode
443−values respectively into or from your content-type's representation.
404+These classes just let you specify a way to encode and decode
405+values into or from your content-type's representation.
444406
445407``` haskell ignore
446408class Accept ctype => MimeRender ctype a where
447− mimeRender :: Proxy ctype -> a -> ByteString
409+ mimeRender :: Proxy ctype -> a -> ByteString
448410 -- alternatively readable as:
449− mimeRender :: Proxy ctype -> (a -> ByteString)
411+ mimeRender :: Proxy ctype -> (a -> ByteString)
450412```
451413
452414Given a content-type and some user type, `MimeRender` provides a function that
@@ -467,14 +429,12 @@ And now the `MimeUnrender` class, which lets us extract values from lazy
467429``` haskell ignore
468430class Accept ctype => MimeUnrender ctype a where
469431 mimeUnrender :: Proxy ctype -> ByteString -> Either String a
470− -- alternatively:
471− mimeUnrender :: Proxy ctype -> (ByteString -> Either String a)
472432```
473433
474434We don't have much work to do there either, `Data.Aeson.eitherDecode` is
475435precisely what we need. However, it only allows arrays and objects as toplevel
476436JSON values and this has proven to get in our way more than help us so we wrote
477−our own little function around *aeson* and *attoparsec* that allows any type of
437+our own little function around **aeson** and **attoparsec** that allows any type of
478438JSON value at the toplevel of a "JSON document". Here's the definition in case
479439you are curious.
480440
@@ -492,21 +452,20 @@ instance FromJSON a => MimeUnrender JSON a where
492452 mimeUnrender _ = eitherDecodeLenient
493453```
494454
495−And this is all the code that lets you use `JSON` for with `ReqBody`, `Get`,
455+And this is all the code that lets you use `JSON` with `ReqBody`, `Get`,
496456`Post` and friends. We can check our understanding by implementing support
497−for an `HTML` content type, so that users of your webservice can access an
457+for an `HTML` content-type, so that users of your webservice can access an
498458HTML representation of the data they want, ready to be included in any HTML
499−document, e.g. using [jQuery's `load` function](https://api.jquery.com/load/), simply by adding `Accept:
500−text/html` to their request headers.
459+document, e.g. using [jQuery's `load` function](https://api.jquery.com/load/),
460+simply by adding `Accept: text/html` to their request headers.
501461
502−Case-studies: *servant-blaze* and *servant-lucid*
503−-------------------------------------------------
462+### Case-studies: **servant-blaze** and **servant-lucid**
504463
505464These days, most of the haskellers who write their HTML UIs directly from
506−Haskell use either [blaze-html](http://hackage.haskell.org/package/blaze-html)
507−or [lucid](http://hackage.haskell.org/package/lucid). The best option for
508−*servant* is obviously to support both (and hopefully other templating
509−solutions!).
465+Haskell use either [**blaze-html**](http://hackage.haskell.org/package/blaze-html)
466+or [**lucid**](http://hackage.haskell.org/package/lucid). The best option for
467+**servant** is obviously to support both (and hopefully other templating
468+solutions!). We're first going to look at **lucid**:
510469
511470``` haskell
512471data HTMLLucid
@@ -514,24 +473,20 @@ data HTMLLucid
514473
515474Once again, the data type is just there as a symbol for the encoding/decoding
516475functions, except that this time we will only worry about encoding since
517−*blaze-html* and *lucid* don't provide a way to extract data from HTML.
518−
519−Both packages also have the same `Accept` instance for their `HTMLLucid` type.
476+**lucid** doesn't provide a way to extract data from HTML.
520477
521478``` haskell
522479instance Accept HTMLLucid where
523480 contentType _ = "text" // "html" /: ("charset", "utf-8")
524481```
525482
526−Note that this instance uses the `(/:)` operator from *http-media* which lets
483+Note that this instance uses the `(/:)` operator from **http-media** which lets
527484us specify additional information about a content-type, like the charset here.
528485
529−The rendering instances for both packages both call similar functions that take
486+The rendering instances call similar functions that take
530487types with an appropriate instance to an "abstract" HTML representation and
531488then write that to a `ByteString`.
532489
533−For *lucid*:
534−
535490``` haskell
536491instance ToHtml a => MimeRender HTMLLucid a where
537492 mimeRender _ = renderBS . toHtml
@@ -542,7 +497,7 @@ instance MimeRender HTMLLucid (Html a) where
542497 mimeRender _ = renderBS
543498```
544499
545−For *blaze-html*:
500+For **blaze-html** everything works very similarly:
546501
547502``` haskell
548503-- For this tutorial to compile 'HTMLLucid' and 'HTMLBlaze' have to be
@@ -562,15 +517,13 @@ instance MimeRender HTMLBlaze Text.Blaze.Html.Html where
562517 mimeRender _ = renderHtml
563518```
564519
565−Both [servant-blaze](http://hackage.haskell.org/package/servant-blaze) and
566−[servant-lucid](http://hackage.haskell.org/package/servant-lucid) let you use
567−`HTMLLucid` in any content type list as long as you provide an instance of the
568−appropriate class (`ToMarkup` for *blaze-html*, `ToHtml` for *lucid*).
569−
570−We can now write webservice that uses *servant-lucid* to show the `HTMLLucid`
571−content type in action. First off, imports and pragmas as usual.
520+Both [**servant-blaze**](http://hackage.haskell.org/package/servant-blaze) and
521+[**servant-lucid**](http://hackage.haskell.org/package/servant-lucid) let you use
522+`HTMLLucid` and `HTMLBlaze` in any content-type list as long as you provide an instance of the
523+appropriate class (`ToMarkup` for **blaze-html**, `ToHtml` for **lucid**).
572524
573−We will be serving the following API:
525+We can now write a webservice that uses **servant-lucid** to show the `HTMLLucid`
526+content-type in action. We will be serving the following API:
574527
575528``` haskell
576529type PersonAPI = "persons" :> Get '[JSON, HTMLLucid] [Person]
@@ -587,7 +540,7 @@ data Person = Person
587540instance ToJSON Person
588541```
589542
590−Now, let's teach *lucid* how to render a `Person` as a row in a table, and then
543+Now, let's teach **lucid** how to render a `Person` as a row in a table, and then
591544a list of `Person`s as a table with a row per person.
592545
593546``` haskell
@@ -618,8 +571,8 @@ instance ToHtml [Person] where
618571We create some `Person` values and serve them as a list:
619572
620573``` haskell
621−persons :: [Person]
622−persons =
574+people :: [Person]
575+people =
623576 [ Person "Isaac" "Newton"
624577 , Person "Albert" "Einstein"
625578 ]
@@ -628,75 +581,69 @@ personAPI :: Proxy PersonAPI
628581personAPI = Proxy
629582
630583server4 :: Server PersonAPI
631−server4 = return persons
584+server4 = return people
632585
633586app2 :: Application
634−app2 = serve personAPI EmptyConfig server4
587+app2 = serve personAPI server4
635588```
636589
637−And we're good to go. You can run this example with `dist/build/tutorial/tutorial 4`.
590+And we're good to go:
638591
639592``` bash
640− $ curl http://localhost:8081/persons
641− [{"lastName":"Newton","firstName":"Isaac"},{"lastName":"Einstein","firstName":"Albert"}]
642− $ curl -H 'Accept: text/html' http://localhost:8081/persons
643− <table><tr><td>first name</td><td>last name</td></tr><tr><td>Isaac</td><td>Newton</td></tr><tr><td>Albert</td><td>Einstein</td></tr></table>
644− # or just point your browser to http://localhost:8081/persons
593+$ curl http://localhost:8081/persons
594+[{"lastName":"Newton","firstName":"Isaac"},{"lastName":"Einstein","firstName":"Albert"}]
595+$ curl -H 'Accept: text/html' http://localhost:8081/persons
596+<table><tr><td>first name</td><td>last name</td></tr><tr><td>Isaac</td><td>Newton</td></tr><tr><td>Albert</td><td>Einstein</td></tr></table>
597+# or just point your browser to http://localhost:8081/persons
645598```
646599
647−The `ExceptT ServantErr IO` monad
648−=================================
600+## The `Handler` monad
649601
650−At the heart of the handlers is the monad they run in, namely `ExceptT
651−ServantErr IO`. One might wonder: why this monad? The answer is that it is the
602+At the heart of the handlers is the monad they run in, namely a newtype `Handler` around `ExceptT ServerError IO`
603+([haddock documentation for `ExceptT`](http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#t:ExceptT)).
604+One might wonder: why this monad? The answer is that it is the
652605simplest monad with the following properties:
653606
654−- it lets us both return a successful result (with the `Right` branch of
655−`Either`) or "fail" with a descriptive error (with the `Left` branch of
656−`Either`);
607+- it lets us both return a successful result (using `return`)
608+or "fail" with a descriptive error (using `throwError`);
657609- it lets us perform IO, which is absolutely vital since most webservices exist
658−as interfaces to databases that we interact with in `IO`;
610+as interfaces to databases that we interact with in `IO`.
659611
660612Let's recall some definitions.
661613
662614``` haskell ignore
663−-- from the Prelude
664−data Either e a = Left e | Right a
665−
666−-- from the 'either' package at
667−-- http://hackage.haskell.org/package/either-4.3.3.2/docs/Control-Monad-Trans-Either.html
668−newtype ExceptT e m a
669− = ExceptT { runEitherT :: m (Either e a) }
615+-- from the 'mtl' package at
616+newtype ExceptT e m a = ExceptT (m (Either e a))
670617```
671618
672−In short, this means that a handler of type `ExceptT ServantErr IO a` is simply
673−equivalent to a computation of type `IO (Either ServantErr a)`, that is, an IO
619+In short, this means that a handler of type `Handler a` is simply
620+equivalent to a computation of type `IO (Either ServerError a)`, that is, an IO
674621action that either returns an error or a result.
675622
676−The aforementioned `either` package is worth taking a look at. Perhaps most
677−importantly:
678−
679−``` haskell ignore
680−left :: Monad m => e -> ExceptT e m a
681−```
682−Allows you to return an error from your handler (whereas `return` is enough to
683−return a success).
623+The module [`Control.Monad.Except`](https://hackage.haskell.org/package/mtl/docs/Control-Monad-Except.html#t:ExceptT)
624+from which `ExceptT` comes is worth looking at.
625+Perhaps most importantly, `ExceptT` and `Handler` are instances of `MonadError`, so
626+`throwError` can be used to return an error from your handler (whereas `return`
627+ is enough to return a success).
684628
685629Most of what you'll be doing in your handlers is running some IO and,
686630depending on the result, you might sometimes want to throw an error of some
687631kind and abort early. The next two sections cover how to do just that.
688632
689−Performing IO
690−-------------
633+### Performing IO
691634
692−Another important instance from the list above is `MonadIO m => MonadIO (ExceptT e m)`. [`MonadIO`](http://hackage.haskell.org/package/transformers-0.4.3.0/docs/Control-Monad-IO-Class.html) is a class from the *transformers* package defined as:
635+Other important instances from the list above are `MonadIO m => MonadIO
636+(ExceptT e m)`, and therefore also `MonadIO Handler` as there is a `MonadIO IO` instance.
637+[`MonadIO`](http://hackage.haskell.org/package/base/docs/Control-Monad-IO-Class.html#t:MonadIO)
638+is a class from the **transformers** package defined as:
693639
694640``` haskell ignore
695641class Monad m => MonadIO m where
696642 liftIO :: IO a -> m a
697643```
698644
699−Obviously, the `IO` monad provides a `MonadIO` instance. Hence for any type `e`, `ExceptT e IO` has a `MonadIO` instance. So if you want to run any kind of IO computation in your handlers, just use `liftIO`:
645+So if you want to run any kind of
646+IO computation in your handlers, just use `liftIO`:
700647
701648``` haskell
702649type IOAPI1 = "myfile.txt" :> Get '[JSON] FileContent
@@ -713,17 +660,16 @@ server5 = do
713660 return (FileContent filecontent)
714661```
715662
716−Failing, through `ServantErr`
717−-----------------------------
663+### Failing, through `ServerError`
718664
719665If you want to explicitly fail at providing the result promised by an endpoint
720666using the appropriate HTTP status code (not found, unauthorized, etc) and some
721−error message, all you have to do is use the `left` function mentioned above
722−and provide it with the appropriate value of type `ServantErr`, which is
667+error message, all you have to do is use the `throwError` function mentioned above
668+and provide it with the appropriate value of type `ServerError`, which is
723669defined as:
724670
725671``` haskell ignore
726−data ServantErr = ServantErr
672+data ServerError = ServerError
727673 { errHTTPCode :: Int
728674 , errReasonPhrase :: String
729675 , errBody :: ByteString -- lazy bytestring
@@ -736,10 +682,10 @@ module. If you want to use these values but add a body or some headers, just
736682use record update syntax:
737683
738684``` haskell
739−failingHandler :: ExceptT ServantErr IO ()
740−failingHandler = throwE myerr
685+failingHandler :: Handler ()
686+failingHandler = throwError myerr
741687
742− where myerr :: ServantErr
688+ where myerr :: ServerError
743689 myerr = err503 { errBody = "Sorry dear user." }
744690```
745691
@@ -752,48 +698,47 @@ server6 = do
752698 exists <- liftIO (doesFileExist "myfile.txt")
753699 if exists
754700 then liftIO (readFile "myfile.txt") >>= return . FileContent
755− else throwE custom404Err
701+ else throwError custom404Err
756702
757703 where custom404Err = err404 { errBody = "myfile.txt just isn't there, please leave this server alone." }
758704```
759705
760−Let's run this server (`dist/build/tutorial/tutorial 5`) and
761−query it, first without the file and then with the file.
706+Here's how that server looks in action:
762707
763708``` bash
764− $ curl --verbose http://localhost:8081/myfile.txt
765− [snip]
766− * Connected to localhost (127.0.0.1) port 8081 (#0)
767− > GET /myfile.txt HTTP/1.1
768− > User-Agent: curl/7.30.0
769− > Host: localhost:8081
770− > Accept: */*
771− >
772− < HTTP/1.1 404 Not Found
773− [snip]
774− myfile.txt just isnt there, please leave this server alone.
775−
776− $ echo Hello > myfile.txt
777−
778− $ curl --verbose http://localhost:8081/myfile.txt
779− [snip]
780− * Connected to localhost (127.0.0.1) port 8081 (#0)
781− > GET /myfile.txt HTTP/1.1
782− > User-Agent: curl/7.30.0
783− > Host: localhost:8081
784− > Accept: */*
785− >
786− < HTTP/1.1 200 OK
787− [snip]
788− < Content-Type: application/json
789− [snip]
790− {"content":"Hello\n"}
791−```
792−
793−Response headers
794−================
795−
796−To add headers to your response, use [addHeader](http://hackage.haskell.org/package/servant-0.4.4/docs/Servant-API-ResponseHeaders.html).
709+$ curl --verbose http://localhost:8081/myfile.txt
710+[snip]
711+* Connected to localhost (127.0.0.1) port 8081 (#0)
712+> GET /myfile.txt HTTP/1.1
713+> User-Agent: curl/7.30.0
714+> Host: localhost:8081
715+> Accept: */*
716+>
717+< HTTP/1.1 404 Not Found
718+[snip]
719+myfile.txt just isn't there, please leave this server alone.
720+
721+$ echo Hello > myfile.txt
722+
723+$ curl --verbose http://localhost:8081/myfile.txt
724+[snip]
725+* Connected to localhost (127.0.0.1) port 8081 (#0)
726+> GET /myfile.txt HTTP/1.1
727+> User-Agent: curl/7.30.0
728+> Host: localhost:8081
729+> Accept: */*
730+>
731+< HTTP/1.1 200 OK
732+[snip]
733+< Content-Type: application/json
734+[snip]
735+{"content":"Hello\n"}
736+```
737+
738+## Response headers
739+
740+To add headers to your response, use
741+[addHeader](http://hackage.haskell.org/package/servant/docs/Servant-API-ResponseHeaders.html).
797742Note that this changes the type of your API, as we can see in the following example:
798743
799744``` haskell
@@ -803,158 +748,89 @@ myHandler :: Server MyHandler
803748myHandler = return $ addHeader 1797 albert
804749```
805750
751+Note that the type of `addHeader header x` is different than the type of `x`!
752+And if you add more headers, more headers will appear in the header list:
753+
754+``` haskell
755+type MyHeadfulHandler = Get '[JSON] (Headers '[Header "X-A-Bool" Bool, Header "X-An-Int" Int] User)
756+
757+myHeadfulHandler :: Server MyHeadfulHandler
758+myHeadfulHandler = return $ addHeader True $ addHeader 1797 albert
759+```
760+
761+But what if your handler only *sometimes* adds a header? If you declare that
762+your handler adds headers, and you don't add one, the return type of your
763+handler will be different than expected. To solve this, you have to explicitly
764+*not* add a header by using `noHeader`:
806765
807−Serving static files
808−====================
766+``` haskell
767+type MyMaybeHeaderHandler
768+ = Capture "withHeader" Bool :> Get '[JSON] (Headers '[Header "X-An-Int" Int] User)
809769
810−*servant-server* also provides a way to just serve the content of a directory
770+myMaybeHeaderHandler :: Server MyMaybeHeaderHandler
771+myMaybeHeaderHandler x = return $ if x then addHeader 1797 albert
772+ else noHeader albert
773+```
774+
775+## Serving static files
776+
777+**servant-server** also provides a way to just serve the content of a directory
811778under some path in your web API. As mentioned earlier in this document, the
812779`Raw` combinator can be used in your APIs to mean "plug here any WAI
813−application". Well, servant-server provides a function to get a file and
780+application". Well, **servant-server** provides a function to get a file and
814781directory serving WAI application, namely:
815782
816783``` haskell ignore
817784-- exported by Servant and Servant.Server
818−serveDirectory :: FilePath -> Server Raw
785+serveDirectoryWebApp :: FilePath -> Server Raw
819786```
820787
821−`serveDirectory`'s argument must be a path to a valid directory. You can see an
822−example below, runnable with `dist/build/tutorial/tutorial 6`
823−(you **must** run it from within the *servant-examples/* directory!), which is
824−a webserver that serves the various bits of code covered in this
825−getting-started.
788+`serveDirectoryWebApp`'s argument must be a path to a valid directory.
826789
827−The API type will be the following.
790+Here's an example API that will serve some static files:
828791
829792``` haskell
830−type CodeAPI = "code" :> Raw
793+type StaticAPI = "static" :> Raw
831794```
832795
833796And the server:
834797
835798``` haskell
836−codeAPI :: Proxy CodeAPI
837−codeAPI = Proxy
799+staticAPI :: Proxy StaticAPI
800+staticAPI = Proxy
838801```
839802
840803``` haskell
841−server7 :: Server CodeAPI
842−server7 = serveDirectory "tutorial"
804+server7 :: Server StaticAPI
805+server7 = serveDirectoryWebApp "static-files"
843806
844807app3 :: Application
845−app3 = serve codeAPI EmptyConfig server7
808+app3 = serve staticAPI server7
846809```
847810
848−This server will match any request whose path starts with `/code` and will look for a file at the path described by the rest of the request path, inside the *tutorial/* directory of the path you run the program from.
811+This server will match any request whose path starts with `/static` and will look
812+for a file at the path described by the rest of the request path, inside the
813+ *static-files/* directory of the path you run the program from.
849814
850−In other words:
815+In other words: If a client requests `/static/foo.txt`, the server will look for a file at
816+`./static-files/foo.txt`. If that file exists it'll succeed and serve the file.
817+If it doesn't exist, the handler will fail with a `404` status code.
851818
852−- If a client requests `/code/foo.txt`, the server will look for a file at `./tutorial/foo.txt` (and fail)
853−- If a client requests `/code/T1.hs`, the server will look for a file at `./tutorial/T1.hs` (and succeed)
854−- If a client requests `/code/foo/bar/baz/movie.mp4`, the server will look for a file at `./tutorial/foo/bar/baz/movie.mp4` (and fail)
819+`serveDirectoryWebApp` uses some standard settings that fit the use case of
820+serving static files for most web apps. You can find out about the other
821+options in the documentation of the `Servant.Server.StaticFiles` module.
855822
856−Here is our little server in action.
823+## Nested APIs
857824
858−``` haskell ignore
859−$ curl http://localhost:8081/code/T1.hs
860−{-# LANGUAGE DataKinds #-}
861−{-# LANGUAGE TypeFamilies #-}
862−{-# LANGUAGE DeriveGeneric #-}
863−{-# LANGUAGE TypeOperators #-}
864−module T1 where
865−
866−import Data.Aeson
867−import Data.Time.Calendar
868−import GHC.Generics
869−import Network.Wai
870−import Servant
871−
872−data User = User
873− { name :: String
874− , age :: Int
875− , email :: String
876− , registration_date :: Day
877− } deriving (Eq, Show, Generic)
878−
879−-- orphan ToJSON instance for Day. necessary to derive one for User
880−instance ToJSON Day where
881− -- display a day in YYYY-mm-dd format
882− toJSON d = toJSON (showGregorian d)
883−
884−instance ToJSON User
885−
886−type UserAPI = "users" :> Get '[JSON] [User]
887−
888−users :: [User]
889−users =
890− [ User "Isaac Newton" 372 "isaac@newton.co.uk" (fromGregorian 1683 3 1)
891− , User "Albert Einstein" 136 "ae@mc2.org" (fromGregorian 1905 12 1)
892− ]
893−
894−userAPI :: Proxy UserAPI
895−userAPI = Proxy
896−
897−server :: Server UserAPI
898−server = return users
899−
900−app :: Application
901−app = serve userAPI server
902−$ curl http://localhost:8081/code/tutorial.hs
903−import Network.Wai
904−import Network.Wai.Handler.Warp
905−import System.Environment
906−
907−import qualified T1
908−import qualified T2
909−import qualified T3
910−import qualified T4
911−import qualified T5
912−import qualified T6
913−import qualified T7
914−import qualified T9
915−import qualified T10
916−
917−app :: String -> (Application -> IO ()) -> IO ()
918−app n f = case n of
919− "1" -> f T1.app
920− "2" -> f T2.app
921− "3" -> f T3.app
922− "4" -> f T4.app
923− "5" -> f T5.app
924− "6" -> f T6.app
925− "7" -> f T7.app
926− "8" -> f T3.app
927− "9" -> T9.writeJSFiles >> f T9.app
928− "10" -> f T10.app
929− _ -> usage
930−
931−main :: IO ()
932−main = do
933− args <- getArgs
934− case args of
935− [n] -> app n (run 8081)
936− _ -> usage
937−
938−usage :: IO ()
939−usage = do
940− putStrLn "Usage:\t tutorial N"
941− putStrLn "\t\twhere N is the number of the example you want to run."
942−
943−$ curl http://localhost:8081/foo
944−not found
945−```
946−
947−Nested APIs
948−===========
949−
950−Let's see how you can define APIs in a modular way, while avoiding repetition. Consider this simple example:
825+Let's see how you can define APIs in a modular way, while avoiding repetition.
826+Consider this simple example:
951827
952828``` haskell
953829type UserAPI3 = -- view the user with given userid, in JSON
954830 Capture "userid" Int :> Get '[JSON] User
955831
956832 :<|> -- delete the user with given userid. empty response
957− Capture "userid" Int :> Delete '[] ()
833+ Capture "userid" Int :> DeleteNoContent
958834```
959835
960836We can instead factor out the `userid`:
@@ -962,32 +838,34 @@ We can instead factor out the `userid`:
962838``` haskell
963839type UserAPI4 = Capture "userid" Int :>
964840 ( Get '[JSON] User
965− :<|> Delete '[] ()
841+ :<|> DeleteNoContent
966842 )
967843```
968844
969−However, you have to be aware that this has an effect on the type of the corresponding `Server`:
845+However, you have to be aware that this has an effect on the type of the
846+corresponding `Server`:
970847
971848``` haskell ignore
972−Server UserAPI3 = (Int -> ExceptT ServantErr IO User)
973− :<|> (Int -> ExceptT ServantErr IO ())
849+Server UserAPI3 = (Int -> Handler User)
850+ :<|> (Int -> Handler NoContent)
974851
975−Server UserAPI4 = Int -> ( ExceptT ServantErr IO User
976− :<|> ExceptT ServantErr IO ()
852+Server UserAPI4 = Int -> ( Handler User
853+ :<|> Handler NoContent
977854 )
978855```
979856
980857In the first case, each handler receives the *userid* argument. In the latter,
981−the whole `Server` takes the *userid* and has handlers that are just computations in `ExceptT`, with no arguments. In other words:
858+the whole `Server` takes the *userid* and has handlers that are just
859+computations in `Handler`, with no arguments. In other words:
982860
983861``` haskell
984862server8 :: Server UserAPI3
985863server8 = getUser :<|> deleteUser
986864
987− where getUser :: Int -> ExceptT ServantErr IO User
865+ where getUser :: Int -> Handler User
988866 getUser _userid = error "..."
989867
990− deleteUser :: Int -> ExceptT ServantErr IO ()
868+ deleteUser :: Int -> Handler NoContent
991869 deleteUser _userid = error "..."
992870
993871-- notice how getUser and deleteUser
@@ -996,14 +874,17 @@ server8 = getUser :<|> deleteUser
996874server9 :: Server UserAPI4
997875server9 userid = getUser userid :<|> deleteUser userid
998876
999− where getUser :: Int -> ExceptT ServantErr IO User
877+ where getUser :: Int -> Handler User
1000878 getUser = error "..."
1001879
1002− deleteUser :: Int -> ExceptT ServantErr IO ()
880+ deleteUser :: Int -> Handler NoContent
1003881 deleteUser = error "..."
1004882```
1005883
1006−Note that there's nothing special about `Capture` that lets you "factor it out": this can be done with any combinator. Here are a few examples of APIs with a combinator factored out for which we can write a perfectly valid `Server`.
884+Note that there's nothing special about `Capture` that lets you "factor it
885+out": this can be done with any combinator. Here are a few examples of APIs
886+with a combinator factored out for which we can write a perfectly valid
887+`Server`.
1007888
1008889``` haskell
1009890-- we just factor out the "users" path fragment
@@ -1015,62 +896,63 @@ type API1 = "users" :>
1015896-- we factor out the Request Body
1016897type API2 = ReqBody '[JSON] User :>
1017898 ( Get '[JSON] User -- just display the same user back, don't register it
1018− :<|> Post '[JSON] () -- register the user. empty response
899+ :<|> PostNoContent -- register the user. empty response
1019900 )
1020901
1021902-- we factor out a Header
1022903type API3 = Header "Authorization" Token :>
1023904 ( Get '[JSON] SecretData -- get some secret data, if authorized
1024− :<|> ReqBody '[JSON] SecretData :> Post '[] () -- add some secret data, if authorized
905+ :<|> ReqBody '[JSON] SecretData :> PostNoContent -- add some secret data, if authorized
1025906 )
1026907
1027908newtype Token = Token ByteString
1028909newtype SecretData = SecretData ByteString
1029910```
1030911
1031−This approach lets you define APIs modularly and assemble them all into one big API type only at the end.
912+This approach lets you define APIs modularly and assemble them all into one big
913+API type only at the end.
1032914
1033915``` haskell
1034916type UsersAPI =
1035917 Get '[JSON] [User] -- list users
1036− :<|> ReqBody '[JSON] User :> Post '[] () -- add a user
918+ :<|> ReqBody '[JSON] User :> PostNoContent -- add a user
1037919 :<|> Capture "userid" Int :>
1038920 ( Get '[JSON] User -- view a user
1039− :<|> ReqBody '[JSON] User :> Put '[] () -- update a user
1040− :<|> Delete '[] () -- delete a user
921+ :<|> ReqBody '[JSON] User :> PutNoContent -- update a user
922+ :<|> DeleteNoContent -- delete a user
1041923 )
1042924
1043925usersServer :: Server UsersAPI
1044926usersServer = getUsers :<|> newUser :<|> userOperations
1045927
1046− where getUsers :: ExceptT ServantErr IO [User]
928+ where getUsers :: Handler [User]
1047929 getUsers = error "..."
1048930
1049− newUser :: User -> ExceptT ServantErr IO ()
931+ newUser :: User -> Handler NoContent
1050932 newUser = error "..."
1051933
1052934 userOperations userid =
1053935 viewUser userid :<|> updateUser userid :<|> deleteUser userid
1054936
1055937 where
1056− viewUser :: Int -> ExceptT ServantErr IO User
938+ viewUser :: Int -> Handler User
1057939 viewUser = error "..."
1058940
1059− updateUser :: Int -> User -> ExceptT ServantErr IO ()
941+ updateUser :: Int -> User -> Handler NoContent
1060942 updateUser = error "..."
1061943
1062− deleteUser :: Int -> ExceptT ServantErr IO ()
944+ deleteUser :: Int -> Handler NoContent
1063945 deleteUser = error "..."
1064946```
1065947
1066948``` haskell
1067949type ProductsAPI =
1068950 Get '[JSON] [Product] -- list products
1069− :<|> ReqBody '[JSON] Product :> Post '[] () -- add a product
951+ :<|> ReqBody '[JSON] Product :> PostNoContent -- add a product
1070952 :<|> Capture "productid" Int :>
1071953 ( Get '[JSON] Product -- view a product
1072− :<|> ReqBody '[JSON] Product :> Put '[] () -- update a product
1073− :<|> Delete '[] () -- delete a product
954+ :<|> ReqBody '[JSON] Product :> PutNoContent -- update a product
955+ :<|> DeleteNoContent -- delete a product
1074956 )
1075957
1076958data Product = Product { productId :: Int }
@@ -1078,23 +960,23 @@ data Product = Product { productId :: Int }
1078960productsServer :: Server ProductsAPI
1079961productsServer = getProducts :<|> newProduct :<|> productOperations
1080962
1081− where getProducts :: ExceptT ServantErr IO [Product]
963+ where getProducts :: Handler [Product]
1082964 getProducts = error "..."
1083965
1084− newProduct :: Product -> ExceptT ServantErr IO ()
966+ newProduct :: Product -> Handler NoContent
1085967 newProduct = error "..."
1086968
1087969 productOperations productid =
1088970 viewProduct productid :<|> updateProduct productid :<|> deleteProduct productid
1089971
1090972 where
1091− viewProduct :: Int -> ExceptT ServantErr IO Product
973+ viewProduct :: Int -> Handler Product
1092974 viewProduct = error "..."
1093975
1094− updateProduct :: Int -> Product -> ExceptT ServantErr IO ()
976+ updateProduct :: Int -> Product -> Handler NoContent
1095977 updateProduct = error "..."
1096978
1097− deleteProduct :: Int -> ExceptT ServantErr IO ()
979+ deleteProduct :: Int -> Handler NoContent
1098980 deleteProduct = error "..."
1099981```
1100982
@@ -1106,139 +988,213 @@ server10 :: Server CombinedAPI
1106988server10 = usersServer :<|> productsServer
1107989```
1108990
1109−Finally, we can realize the user and product APIs are quite similar and abstract that away:
991+Finally, we can realize the user and product APIs are quite similar and
992+abstract that away:
1110993
1111994``` haskell
1112995-- API for values of type 'a'
1113996-- indexed by values of type 'i'
1114997type APIFor a i =
1115998 Get '[JSON] [a] -- list 'a's
1116− :<|> ReqBody '[JSON] a :> Post '[] () -- add an 'a'
999+ :<|> ReqBody '[JSON] a :> PostNoContent -- add an 'a'
11171000 :<|> Capture "id" i :>
11181001 ( Get '[JSON] a -- view an 'a' given its "identifier" of type 'i'
1119− :<|> ReqBody '[JSON] a :> Put '[] () -- update an 'a'
1120− :<|> Delete '[] () -- delete an 'a'
1002+ :<|> ReqBody '[JSON] a :> PutNoContent -- update an 'a'
1003+ :<|> DeleteNoContent -- delete an 'a'
11211004 )
11221005
11231006-- Build the appropriate 'Server'
11241007-- given the handlers of the right type.
1125−serverFor :: ExceptT ServantErr IO [a] -- handler for listing of 'a's
1126− -> (a -> ExceptT ServantErr IO ()) -- handler for adding an 'a'
1127− -> (i -> ExceptT ServantErr IO a) -- handler for viewing an 'a' given its identifier of type 'i'
1128− -> (i -> a -> ExceptT ServantErr IO ()) -- updating an 'a' with given id
1129− -> (i -> ExceptT ServantErr IO ()) -- deleting an 'a' given its id
1008+serverFor :: Handler [a] -- handler for listing of 'a's
1009+ -> (a -> Handler NoContent) -- handler for adding an 'a'
1010+ -> (i -> Handler a) -- handler for viewing an 'a' given its identifier of type 'i'
1011+ -> (i -> a -> Handler NoContent) -- updating an 'a' with given id
1012+ -> (i -> Handler NoContent) -- deleting an 'a' given its id
11301013 -> Server (APIFor a i)
11311014serverFor = error "..."
11321015-- implementation left as an exercise. contact us on IRC
11331016-- or the mailing list if you get stuck!
11341017```
11351018
1136−Using another monad for your handlers
1137−=====================================
1019+When your API contains the `EmptyAPI` combinator, you'll want to use
1020+`emptyServer` in the corresponding slot for your server, which will simply fail
1021+with 404 whenever a request reaches it:
11381022
1139−Remember how `Server` turns combinators for HTTP methods into `ExceptT ServantErr IO`? Well, actually, there's more to that. `Server` is actually a simple type synonym.
1023+``` haskell
1024+type CombinedAPI2 = API :<|> "empty" :> EmptyAPI
1025+
1026+server11 :: Server CombinedAPI2
1027+server11 = server3 :<|> emptyServer
1028+```
1029+
1030+## Using another monad for your handlers
1031+
1032+Remember how `Server` turns combinators for HTTP methods into `Handler`? Well, actually, there's more to that. `Server` is actually a
1033+simple type synonym.
11401034
11411035``` haskell ignore
1142−type Server api = ServerT api (ExceptT ServantErr IO)
1036+type Server api = ServerT api Handler
11431037```
11441038
1145−`ServerT` is the actual type family that computes the required types for the handlers that's part of the `HasServer` class. It's like `Server` except that it takes a third parameter which is the monad you want your handlers to run in, or more generally the return types of your handlers. This third parameter is used for specifying the return type of the handler for an endpoint, e.g when computing `ServerT (Get '[JSON] Person) SomeMonad`. The result would be `SomeMonad Person`.
1039+`ServerT` is the actual type family that computes the required types for the
1040+handlers that's part of the `HasServer` class. It's like `Server` except that
1041+it takes another parameter which is the monad you want your handlers to run in,
1042+or more generally the return types of your handlers. This third parameter is
1043+used for specifying the return type of the handler for an endpoint, e.g when
1044+computing `ServerT (Get '[JSON] Person) SomeMonad`. The result would be
1045+`SomeMonad Person`.
11461046
1147−The first and main question one might have then is: how do we write handlers that run in another monad? How can we "bring back" the value from a given monad into something *servant* can understand?
1047+The first and main question one might have then is: how do we write handlers
1048+that run in another monad? How can we "bring back" the value from a given monad
1049+into something **servant** can understand?
11481050
1149−Natural transformations
1150−-----------------------
1051+### Natural transformations
11511052
11521053If we have a function that gets us from an `m a` to an `n a`, for any `a`, what
11531054do we have?
11541055
1155−``` haskell ignore
1156−newtype m :~> n = Nat { unNat :: forall a. m a -> n a}
1056+``` haskell
1057+type (~>) m n = forall a. m a -> n a
1058+```
1059+
1060+For example:
11571061
1158−-- For example
1159−-- listToMaybeNat ::`[] :~> Maybe`
1160−-- listToMaybeNat = Nat listToMaybe -- from Data.Maybe
1062+``` haskell
1063+listToMaybe' :: [] ~> Maybe
1064+listToMaybe' = listToMaybe -- from Data.Maybe
11611065```
1162−(`Nat` comes from "natural transformation", in case you're wondering.)
11631066
1164−So if you want to write handlers using another monad/type than `ExceptT
1165−ServantErr IO`, say the `Reader String` monad, the first thing you have to
1067+Note that `servant` doesn't declare the `~>` type-alias, as the unfolded
1068+variant isn't much longer to write, as we'll see shortly.
1069+
1070+So if you want to write handlers using another monad/type than `Handler`, say the `Reader String` monad, the first thing you have to
11661071prepare is a function:
11671072
11681073``` haskell ignore
1169−readerToEither :: Reader String :~> ExceptT ServantErr IO
1074+readerToHandler :: Reader String a -> Handler a
11701075```
11711076
1172−Let's start with `readerToEither'`. We obviously have to run the `Reader`
1173−computation by supplying it with a `String`, like `"hi"`. We get an `a` out
1174−from that and can then just `return` it into `ExceptT`. We can then just wrap
1175−that function with the `Nat` constructor to make it have the fancier type.
1077+We obviously have to run the `Reader` computation by supplying it with a
1078+`String`, like `"hi"`. We get an `a` out from that and can then just `return`
1079+it into `Handler`.
11761080
11771081``` haskell
1178−readerToEither' :: forall a. Reader String a -> ExceptT ServantErr IO a
1179−readerToEither' r = return (runReader r "hi")
1180−
1181−readerToEither :: Reader String :~> ExceptT ServantErr IO
1182−readerToEither = Nat readerToEither'
1082+readerToHandler :: Reader String a -> Handler a
1083+readerToHandler r = return (runReader r "hi")
11831084```
11841085
11851086We can write some simple webservice with the handlers running in `Reader String`.
11861087
11871088``` haskell
11881089type ReaderAPI = "a" :> Get '[JSON] Int
1189− :<|> "b" :> Get '[JSON] String
1090+ :<|> "b" :> ReqBody '[JSON] Double :> Get '[JSON] Bool
11901091
11911092readerAPI :: Proxy ReaderAPI
11921093readerAPI = Proxy
11931094
11941095readerServerT :: ServerT ReaderAPI (Reader String)
1195−readerServerT = a :<|> b
1196−
1197− where a :: Reader String Int
1198− a = return 1797
1096+readerServerT = a :<|> b where
1097+ a :: Reader String Int
1098+ a = return 1797
11991099
1200− b :: Reader String String
1201− b = ask
1100+ b :: Double -> Reader String Bool
1101+ b _ = asks (== "hi")
12021102```
12031103
12041104We unfortunately can't use `readerServerT` as an argument of `serve`, because
1205−`serve` wants a `Server ReaderAPI`, i.e., with handlers running in `ExceptT
1206−ServantErr IO`. But there's a simple solution to this.
1105+`serve` wants a `Server ReaderAPI`, i.e., with handlers running in `Handler`. But there's a simple solution to this.
12071106
1208−Enter `enter`
1209−-------------
1107+### Welcome `hoistServer`
12101108
1211−That's right. We have just written `readerToEither`, which is exactly what we
1212−would need to apply to the results of all handlers to make the handlers have the
1109+That's right. We have just written `readerToHandler`, which is exactly what we
1110+would need to apply to all handlers to make the handlers have the
12131111right type for `serve`. Being cumbersome to do by hand, we provide a function
1214−`enter` which takes a natural transformation between two parametrized types `m`
1112+`hoistServer` which takes a natural transformation between two parameterized types `m`
12151113and `n` and a `ServerT someapi m`, and returns a `ServerT someapi n`.
12161114
1217−In our case, we can wrap up our little webservice by using `enter readerToEither` on our handlers.
1115+In our case, we can wrap up our little webservice by using
1116+`hoistServer readerAPI readerToHandler` on our handlers.
12181117
12191118``` haskell
12201119readerServer :: Server ReaderAPI
1221−readerServer = enter readerToEither readerServerT
1120+readerServer = hoistServer readerAPI readerToHandler readerServerT
12221121
12231122app4 :: Application
1224−app4 = serve readerAPI EmptyConfig readerServer
1123+app4 = serve readerAPI readerServer
12251124```
12261125
1227−And we can indeed see this webservice in action by running `dist/build/tutorial/tutorial 7`.
1126+This is the webservice in action:
12281127
12291128``` bash
12301129$ curl http://localhost:8081/a
123111301797
1232−$ curl http://localhost:8081/b
1233−"hi"
1131+$ curl http://localhost:8081/b -X GET -d '42.0' -H 'Content-Type: application/json'
1132+true
1133+```
1134+
1135+### An arrow is a reader too.
1136+
1137+In previous versions of `servant` we had an `enter` to do what `hoistServer`
1138+does now. `enter` had an ambitious design goals, but was problematic in practice.
1139+
1140+One problematic situation was when the source monad was `(->) r`, yet it's
1141+handy in practice, because `(->) r` is isomorphic to `Reader r`.
1142+
1143+We can rewrite the previous example without `Reader`:
1144+
1145+```haskell
1146+funServerT :: ServerT ReaderAPI ((->) String)
1147+funServerT = a :<|> b where
1148+ a :: String -> Int
1149+ a _ = 1797
1150+
1151+ -- unfortunately, we cannot make `String` the first argument.
1152+ b :: Double -> String -> Bool
1153+ b _ s = s == "hi"
1154+
1155+funToHandler :: (String -> a) -> Handler a
1156+funToHandler f = return (f "hi")
1157+
1158+app5 :: Application
1159+app5 = serve readerAPI (hoistServer readerAPI funToHandler funServerT)
1160+```
1161+
1162+## Streaming endpoints
1163+
1164+We can create endpoints that don't just give back a single result, but give
1165+back a *stream* of results, served one at a time. Stream endpoints only provide
1166+a single content type, and also specify what framing strategy is used to
1167+delineate the results. To serve these results, we need to give back a stream
1168+producer. Adapters can be written to *Pipes*, *Conduit* and the like, or
1169+written directly as `SourceIO`s. SourceIO builds upon servant's own `SourceT`
1170+stream type (it's simpler than *Pipes* or *Conduit*).
1171+The API of a streaming endpoint needs to explicitly specify which sort of
1172+generator it produces. Note that the generator itself is returned by a
1173+`Handler` action, so that additional IO may be done in the creation of one.
1174+
1175+``` haskell
1176+type StreamAPI = "userStream" :> StreamGet NewlineFraming JSON (SourceIO User)
1177+streamAPI :: Proxy StreamAPI
1178+streamAPI = Proxy
1179+
1180+streamUsers :: SourceIO User
1181+streamUsers = source [isaac, albert, albert]
1182+
1183+app6 :: Application
1184+app6 = serve streamAPI (return streamUsers)
12341185```
12351186
1236−Conclusion
1237−==========
1187+This simple application returns a stream of `User` values encoded in JSON
1188+format, with each value separated by a newline. In this case, the stream will
1189+consist of the value of `isaac`, followed by the value of `albert`, then the
1190+value of `albert` a second time. Importantly, the stream is written back as
1191+results are produced, rather than all at once. This means first that results
1192+are delivered when they are available, and second, that if an exception
1193+interrupts production of the full stream, nonetheless partial results have
1194+already been written back.
12381195
1239−You're now equipped to write any kind of webservice/web-application using *servant*. One thing not covered here is how to incorporate your own combinators and will be the topic of a page on the website. The rest of this document focuses on *servant-client*, *servant-jquery* and *servant-docs*.
1196+## Conclusion
12401197
1241−<div style="text-align: center;">
1242− <p><a href="/tutorial/api-type.html">Previous page: A web API as a type</a></p>
1243− <p><a href="/tutorial/client.html">Next page: Deriving Haskell functions to query an API</a></p>
1244−</div>
1198+You're now equipped to write webservices/web-applications using
1199+**servant**. The rest of this document focuses on **servant-client**,
1200+**servant-js** and **servant-docs**.