@@ -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,20 +18,23 @@ 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
4725module Server where
4826
49−import Control.Monad.IO.Class
27+import Prelude ()
28+import Prelude.Compat
29+
30+import Control.Monad.Except
5031import Control.Monad.Reader
51−import Control.Monad.Trans.Either
5232import Data.Aeson
5333import Data.Aeson.Types
5434import Data.Attoparsec.ByteString
5535import Data.ByteString (ByteString)
56−import Data.Int
5736import Data.List
37+import Data.Maybe
5838import Data.String.Conversions
5939import Data.Time.Calendar
6040import GHC.Generics
@@ -66,15 +46,18 @@ import Servant
6646import System.Directory
6747import Text.Blaze
6848import Text.Blaze.Html.Renderer.Utf8
49+import Servant.Types.SourceT (source)
6950import qualified Data.Aeson.Parser
7051import qualified Text.Blaze.Html
7152```
7253
73−``` haskell ignore
74−{-# LANGUAGE TypeFamilies #-}
75−```
76−
77−**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.
7861
7962We will write a server that will serve the following API.
8063
@@ -113,12 +96,6 @@ users1 =
11396 ]
11497```
11598
116−Let's also write our API type.
117−
118−``` haskell ignore
119−type UserAPI1 = "users" :> Get '[JSON] [User]
120−```
121−
12299We can now take care of writing the actual webservice that will handle requests
123100to such an API. This one will be very simple, being reduced to just a single
124101endpoint. The type of the web application is determined by the API type,
@@ -130,11 +107,11 @@ corresponding API type.
130107The first thing to know about the `Server` type family is that behind the
131108scenes it will drive the routing, letting you focus only on the business
132109logic. The second thing to know is that for each endpoint, your handlers will
133−by default run in the `EitherT ServantErr IO` monad. This is overridable very
110+by default run in the `Handler` monad. This is overridable very
134111easily, as explained near the end of this guide. Third thing, the type of the
135112value returned in that monad must be the same as the second argument of the
136113HTTP method combinator used for the corresponding endpoint. In our case, it
137−means we must provide a handler of type `EitherT ServantErr IO [User]`. Well,
114+means we must provide a handler of type `Handler [User]`. Well,
138115we have a monad, let's just `return` our list:
139116
140117``` haskell
@@ -142,7 +119,9 @@ server1 :: Server UserAPI1
142119server1 = return users1
143120```
144121
145−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):
146125
147126``` haskell
148127userAPI :: Proxy UserAPI1
@@ -167,9 +146,8 @@ main = run 8081 app1
167146
168147You can put this all into a file or just grab [servant's
169148repo](http://github.com/haskell-servant/servant) and look at the
170−*servant-examples* directory. The code we have just explored is in
171−*tutorial/T1.hs*, runnable with
172−`dist/build/tutorial/tutorial 1`.
149+*doc/tutorial* directory. This code (the source of this web page) is in
150+*doc/tutorial/Server.lhs*.
173151
174152If you run it, you can go to `http://localhost:8081/users` in your browser or
175153query it with curl and you see:
@@ -179,10 +157,10 @@ $ curl http://localhost:8081/users
179157[{"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"}]
180158```
181159
182−More endpoints
183−==============
160+## More endpoints
184161
185−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.
186164
187165``` haskell
188166type UserAPI2 = "users" :> Get '[JSON] [User]
@@ -205,7 +183,7 @@ users2 = [isaac, albert]
205183
206184Now, just like we separate the various endpoints in `UserAPI` with `:<|>`, we
207185are going to separate the handlers with `:<|>` too! They must be provided in
208−the same order as the one they appear in in the API type.
186+the same order as in the API type.
209187
210188``` haskell
211189server2 :: Server UserAPI2
@@ -214,22 +192,21 @@ server2 = return users2
214192 :<|> return isaac
215193```
216194
217−And that's it! You can run this example with
218−`dist/build/tutorial/tutorial 2` and check out the data available
219−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`.
220197
221−From combinators to handler arguments
222−=====================================
198+## From combinators to handler arguments
223199
224200Fine, we can write trivial webservices easily, but none of the two above use
225201any "fancy" combinator from servant. Let's address this and use `QueryParam`,
226−`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
227203combinators in an endpoint makes the corresponding handler receive an
228204argument of the appropriate type automatically. You don't have to worry about
229205manually looking up URL captures or query string parameters, or
230206decoding/encoding data from/to JSON. Never.
231207
232−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`.
233210
234211``` haskell
235212type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
@@ -237,8 +214,8 @@ type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Posit
237214 :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email
238215
239216data Position = Position
240− { x :: Int
241− , y :: Int
217+ { xCoord :: Int
218+ , yCoord :: Int
242219 } deriving Generic
243220
244221instance ToJSON Position
@@ -288,15 +265,15 @@ server3 = position
288265 :<|> hello
289266 :<|> marketing
290267
291− where position :: Int -> Int -> EitherT ServantErr IO Position
268+ where position :: Int -> Int -> Handler Position
292269 position x y = return (Position x y)
293270
294− hello :: Maybe String -> EitherT ServantErr IO HelloMessage
271+ hello :: Maybe String -> Handler HelloMessage
295272 hello mname = return . HelloMessage $ case mname of
296273 Nothing -> "Hello, anonymous coward"
297274 Just n -> "Hello, " ++ n
298275
299− marketing :: ClientInfo -> EitherT ServantErr IO Email
276+ marketing :: ClientInfo -> Handler Email
300277 marketing clientinfo = return (emailForClient clientinfo)
301278```
302279
@@ -311,114 +288,86 @@ parameter might not always be there);
311288
312289 - a `ReqBody contentTypeList a` becomes an argument of type `a`;
313290
314−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:
315292
316293``` bash
317294$ curl http://localhost:8081/position/1/2
318−{"x":1,"y":2}
295+{"xCoord":1,"yCoord":2}
319296$ curl http://localhost:8081/hello
320297{"msg":"Hello, anonymous coward"}
321298$ curl http://localhost:8081/hello?name=Alp
322299{"msg":"Hello, Alp"}
323−$ 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
324301{"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"}
325302```
326303
327−For reference, here's a list of some combinators from *servant* and for those
328−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**:
329305
330− > - `Delete`, `Get`, `Patch`, `Post`, `Put`: these do not become arguments. They provide the return type of handlers, which usually is `EitherT 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>`.
331307 > - `Capture "something" a` becomes an argument of type `a`.
332− > - `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.
333− > - `QueryFlag "something"` and `MatrixFlag "something"` get turned into arguments of type `Bool`.
334− > - `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]`.
335311 > - `ReqBody contentTypes a` gets turned into an argument of type `a`.
336312
337−The `FromText`/`ToText` classes
338−===============================
313+## The `FromHttpApiData`/`ToHttpApiData` classes
339314
340−Wait... How does *servant* know how to decode the `Int`s from the URL? Or how
341−to decode a `ClientInfo` value from the request body? This is what this and the
342−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.
343318
344319`Capture`s and `QueryParam`s are represented by some textual value in URLs.
345320`Header`s are similarly represented by a pair of a header name and a
346−corresponding (textual) value in the request's "metadata". This is why we
347−decided to provide a pair of typeclasses, `FromText` and `ToText` which just
348−let you say that you can respectively *extract* or *encode* values of some type
349−*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)):
350325
351326``` haskell ignore
352−class FromText a where
353− fromText :: Text -> Maybe a
354−
355−class ToText a where
356− toText :: a -> Text
357−```
358−
359−And as long as the type that a `Capture`/`QueryParam`/`Header`/etc will be
360−decoded to provides a `FromText` instance, it will Just Work. *servant*
361−provides a decent number of instances, but here are some examples of defining
362−your own.
363−
364−``` haskell
365−-- A typical enumeration
366−data Direction
367− = Up
368− | Down
369− | Left
370− | Right
371−
372−instance FromText Direction where
373− -- requires {-# LANGUAGE OverloadedStrings #-}
374− fromText "up" = Just Up
375− fromText "down" = Just Down
376− fromText "left" = Just Server.Left
377− fromText "right" = Just Server.Right
378− fromText _ = Nothing
327+class FromHttpApiData a where
328+ {-# MINIMAL parseUrlPiece | parseQueryParam #-}
329+ -- | Parse URL path piece.
330+ parseUrlPiece :: Text -> Either Text a
331+ parseUrlPiece = parseQueryParam
379332
380−instance ToText Direction where
381− toText Up = "up"
382− toText Down = "down"
383− toText Server.Left = "left"
384− toText Server.Right = "right"
333+ -- | Parse HTTP header value.
334+ parseHeader :: ByteString -> Either Text a
335+ parseHeader = parseUrlPiece . decodeUtf8
385336
386−newtype UserId = UserId Int64
387− deriving (FromText, ToText)
337+ -- | Parse query param value.
338+ parseQueryParam :: Text -> Either Text a
339+ parseQueryParam = parseUrlPiece
388340```
389341
390−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.
391345
392−``` haskell ignore
393−instance FromText UserId where
394− fromText = fmap UserId fromText
395−
396−instance ToText UserId where
397− toText (UserId i) = toText i
398−```
346+**http-api-data** provides a decent number of instances, helpers for defining new
347+ones, and wonderful documentation.
399348
400349There's not much else to say about these classes. You will need instances for
401−them when using `Capture`, `QueryParam`, `QueryParams`, `MatrixParam`,
402−`MatrixParams` and `Header` with your types. You will need `FromText` instances
403−for server-side request handlers and `ToText` instances only when using
404−*servant-client*, as described in the [section about deriving haskell
405−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).
406355
407−Using content-types with your data types
408−========================================
356+## Using content-types with your data types
409357
410358The same principle was operating when decoding request bodies from JSON, and
411359responses *into* JSON. (JSON is just the running example - you can do this with
412360any content-type.)
413361
414−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
415363all of this work.
416364
417−The truth behind `JSON`
418−-----------------------
365+### The truth behind `JSON`
366+
419367
420−What exactly is `JSON`? Like the 3 other content types provided out of the box
421−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.
422371
423372``` haskell ignore
424373data JSON
@@ -428,14 +377,15 @@ data OctetStream
428377```
429378
430379Obviously, this is not all there is to `JSON`, otherwise it would be quite
431−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
432381a special *symbol* that's associated with encoding (resp. decoding) to (resp.
433382from) the *JSON* format. The way this association is performed can be
434383decomposed into two steps.
435384
436385The first step is to provide a proper
437−[`MediaType`](https://hackage.haskell.org/package/http-media-0.6.2/docs/Network-HTTP-Media.html)
438−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
439389haddocks from this link, you can see that we just have to specify
440390`application/json` using the appropriate functions. In our case, we can just
441391use `(//) :: ByteString -> ByteString -> MediaType`. The precise way to specify
@@ -451,14 +401,14 @@ instance Accept JSON where
451401```
452402
453403The second step is centered around the `MimeRender` and `MimeUnrender` classes.
454−These classes just let you specify a way to respectively encode and decode
455−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.
456406
457407``` haskell ignore
458408class Accept ctype => MimeRender ctype a where
459− mimeRender :: Proxy ctype -> a -> ByteString
409+ mimeRender :: Proxy ctype -> a -> ByteString
460410 -- alternatively readable as:
461− mimeRender :: Proxy ctype -> (a -> ByteString)
411+ mimeRender :: Proxy ctype -> (a -> ByteString)
462412```
463413
464414Given a content-type and some user type, `MimeRender` provides a function that
@@ -479,14 +429,12 @@ And now the `MimeUnrender` class, which lets us extract values from lazy
479429``` haskell ignore
480430class Accept ctype => MimeUnrender ctype a where
481431 mimeUnrender :: Proxy ctype -> ByteString -> Either String a
482− -- alternatively:
483− mimeUnrender :: Proxy ctype -> (ByteString -> Either String a)
484432```
485433
486434We don't have much work to do there either, `Data.Aeson.eitherDecode` is
487435precisely what we need. However, it only allows arrays and objects as toplevel
488436JSON values and this has proven to get in our way more than help us so we wrote
489−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
490438JSON value at the toplevel of a "JSON document". Here's the definition in case
491439you are curious.
492440
@@ -504,21 +452,20 @@ instance FromJSON a => MimeUnrender JSON a where
504452 mimeUnrender _ = eitherDecodeLenient
505453```
506454
507−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`,
508456`Post` and friends. We can check our understanding by implementing support
509−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
510458HTML representation of the data they want, ready to be included in any HTML
511−document, e.g. using [jQuery's `load` function](https://api.jquery.com/load/), simply by adding `Accept:
512−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.
513461
514−Case-studies: *servant-blaze* and *servant-lucid*
515−-------------------------------------------------
462+### Case-studies: **servant-blaze** and **servant-lucid**
516463
517464These days, most of the haskellers who write their HTML UIs directly from
518−Haskell use either [blaze-html](http://hackage.haskell.org/package/blaze-html)
519−or [lucid](http://hackage.haskell.org/package/lucid). The best option for
520−*servant* is obviously to support both (and hopefully other templating
521−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**:
522469
523470``` haskell
524471data HTMLLucid
@@ -526,24 +473,20 @@ data HTMLLucid
526473
527474Once again, the data type is just there as a symbol for the encoding/decoding
528475functions, except that this time we will only worry about encoding since
529−*blaze-html* and *lucid* don't provide a way to extract data from HTML.
530−
531−Both packages also have the same `Accept` instance for their `HTMLLucid` type.
476+**lucid** doesn't provide a way to extract data from HTML.
532477
533478``` haskell
534479instance Accept HTMLLucid where
535480 contentType _ = "text" // "html" /: ("charset", "utf-8")
536481```
537482
538−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
539484us specify additional information about a content-type, like the charset here.
540485
541−The rendering instances for both packages both call similar functions that take
486+The rendering instances call similar functions that take
542487types with an appropriate instance to an "abstract" HTML representation and
543488then write that to a `ByteString`.
544489
545−For *lucid*:
546−
547490``` haskell
548491instance ToHtml a => MimeRender HTMLLucid a where
549492 mimeRender _ = renderBS . toHtml
@@ -554,7 +497,7 @@ instance MimeRender HTMLLucid (Html a) where
554497 mimeRender _ = renderBS
555498```
556499
557−For *blaze-html*:
500+For **blaze-html** everything works very similarly:
558501
559502``` haskell
560503-- For this tutorial to compile 'HTMLLucid' and 'HTMLBlaze' have to be
@@ -574,15 +517,13 @@ instance MimeRender HTMLBlaze Text.Blaze.Html.Html where
574517 mimeRender _ = renderHtml
575518```
576519
577−Both [servant-blaze](http://hackage.haskell.org/package/servant-blaze) and
578−[servant-lucid](http://hackage.haskell.org/package/servant-lucid) let you use
579−`HTMLLucid` in any content type list as long as you provide an instance of the
580−appropriate class (`ToMarkup` for *blaze-html*, `ToHtml` for *lucid*).
581−
582−We can now write webservice that uses *servant-lucid* to show the `HTMLLucid`
583−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**).
584524
585−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:
586527
587528``` haskell
588529type PersonAPI = "persons" :> Get '[JSON, HTMLLucid] [Person]
@@ -599,7 +540,7 @@ data Person = Person
599540instance ToJSON Person
600541```
601542
602−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
603544a list of `Person`s as a table with a row per person.
604545
605546``` haskell
@@ -630,8 +571,8 @@ instance ToHtml [Person] where
630571We create some `Person` values and serve them as a list:
631572
632573``` haskell
633−persons :: [Person]
634−persons =
574+people :: [Person]
575+people =
635576 [ Person "Isaac" "Newton"
636577 , Person "Albert" "Einstein"
637578 ]
@@ -640,75 +581,69 @@ personAPI :: Proxy PersonAPI
640581personAPI = Proxy
641582
642583server4 :: Server PersonAPI
643−server4 = return persons
584+server4 = return people
644585
645586app2 :: Application
646587app2 = serve personAPI server4
647588```
648589
649−And we're good to go. You can run this example with `dist/build/tutorial/tutorial 4`.
590+And we're good to go:
650591
651592``` bash
652− $ curl http://localhost:8081/persons
653− [{"lastName":"Newton","firstName":"Isaac"},{"lastName":"Einstein","firstName":"Albert"}]
654− $ curl -H 'Accept: text/html' http://localhost:8081/persons
655− <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>
656− # 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
657598```
658599
659−The `EitherT ServantErr IO` monad
660−=================================
600+## The `Handler` monad
661601
662−At the heart of the handlers is the monad they run in, namely `EitherT
663−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
664605simplest monad with the following properties:
665606
666−- it lets us both return a successful result (with the `Right` branch of
667−`Either`) or "fail" with a descriptive error (with the `Left` branch of
668−`Either`);
607+- it lets us both return a successful result (using `return`)
608+or "fail" with a descriptive error (using `throwError`);
669609- it lets us perform IO, which is absolutely vital since most webservices exist
670−as interfaces to databases that we interact with in `IO`;
610+as interfaces to databases that we interact with in `IO`.
671611
672612Let's recall some definitions.
673613
674614``` haskell ignore
675−-- from the Prelude
676−data Either e a = Left e | Right a
677−
678−-- from the 'either' package at
679−-- http://hackage.haskell.org/package/either-4.3.3.2/docs/Control-Monad-Trans-Either.html
680−newtype EitherT e m a
681− = EitherT { runEitherT :: m (Either e a) }
615+-- from the 'mtl' package at
616+newtype ExceptT e m a = ExceptT (m (Either e a))
682617```
683618
684−In short, this means that a handler of type `EitherT ServantErr IO a` is simply
685−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
686621action that either returns an error or a result.
687622
688−The aforementioned `either` package is worth taking a look at. Perhaps most
689−importantly:
690−
691−``` haskell ignore
692−left :: Monad m => e -> EitherT e m a
693−```
694−Allows you to return an error from your handler (whereas `return` is enough to
695−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).
696628
697629Most of what you'll be doing in your handlers is running some IO and,
698630depending on the result, you might sometimes want to throw an error of some
699631kind and abort early. The next two sections cover how to do just that.
700632
701−Performing IO
702−-------------
633+### Performing IO
703634
704−Another important instance from the list above is `MonadIO m => MonadIO (EitherT 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:
705639
706640``` haskell ignore
707641class Monad m => MonadIO m where
708642 liftIO :: IO a -> m a
709643```
710644
711−Obviously, the `IO` monad provides a `MonadIO` instance. Hence for any type `e`, `EitherT 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`:
712647
713648``` haskell
714649type IOAPI1 = "myfile.txt" :> Get '[JSON] FileContent
@@ -725,17 +660,16 @@ server5 = do
725660 return (FileContent filecontent)
726661```
727662
728−Failing, through `ServantErr`
729−-----------------------------
663+### Failing, through `ServerError`
730664
731665If you want to explicitly fail at providing the result promised by an endpoint
732666using the appropriate HTTP status code (not found, unauthorized, etc) and some
733−error message, all you have to do is use the `left` function mentioned above
734−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
735669defined as:
736670
737671``` haskell ignore
738−data ServantErr = ServantErr
672+data ServerError = ServerError
739673 { errHTTPCode :: Int
740674 , errReasonPhrase :: String
741675 , errBody :: ByteString -- lazy bytestring
@@ -748,10 +682,10 @@ module. If you want to use these values but add a body or some headers, just
748682use record update syntax:
749683
750684``` haskell
751−failingHandler :: EitherT ServantErr IO ()
752−failingHandler = left myerr
685+failingHandler :: Handler ()
686+failingHandler = throwError myerr
753687
754− where myerr :: ServantErr
688+ where myerr :: ServerError
755689 myerr = err503 { errBody = "Sorry dear user." }
756690```
757691
@@ -764,48 +698,47 @@ server6 = do
764698 exists <- liftIO (doesFileExist "myfile.txt")
765699 if exists
766700 then liftIO (readFile "myfile.txt") >>= return . FileContent
767− else left custom404Err
701+ else throwError custom404Err
768702
769703 where custom404Err = err404 { errBody = "myfile.txt just isn't there, please leave this server alone." }
770704```
771705
772−Let's run this server (`dist/build/tutorial/tutorial 5`) and
773−query it, first without the file and then with the file.
706+Here's how that server looks in action:
774707
775708``` bash
776− $ curl --verbose http://localhost:8081/myfile.txt
777− [snip]
778− * Connected to localhost (127.0.0.1) port 8081 (#0)
779− > GET /myfile.txt HTTP/1.1
780− > User-Agent: curl/7.30.0
781− > Host: localhost:8081
782− > Accept: */*
783− >
784− < HTTP/1.1 404 Not Found
785− [snip]
786− myfile.txt just isnt there, please leave this server alone.
787−
788− $ echo Hello > myfile.txt
789−
790− $ curl --verbose http://localhost:8081/myfile.txt
791− [snip]
792− * Connected to localhost (127.0.0.1) port 8081 (#0)
793− > GET /myfile.txt HTTP/1.1
794− > User-Agent: curl/7.30.0
795− > Host: localhost:8081
796− > Accept: */*
797− >
798− < HTTP/1.1 200 OK
799− [snip]
800− < Content-Type: application/json
801− [snip]
802− {"content":"Hello\n"}
803−```
804−
805−Response headers
806−================
807−
808−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).
809742Note that this changes the type of your API, as we can see in the following example:
810743
811744``` haskell
@@ -815,158 +748,89 @@ myHandler :: Server MyHandler
815748myHandler = return $ addHeader 1797 albert
816749```
817750
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`:
818765
819−Serving static files
820−====================
766+``` haskell
767+type MyMaybeHeaderHandler
768+ = Capture "withHeader" Bool :> Get '[JSON] (Headers '[Header "X-An-Int" Int] User)
769+
770+myMaybeHeaderHandler :: Server MyMaybeHeaderHandler
771+myMaybeHeaderHandler x = return $ if x then addHeader 1797 albert
772+ else noHeader albert
773+```
821774
822−*servant-server* also provides a way to just serve the content of a directory
775+## Serving static files
776+
777+**servant-server** also provides a way to just serve the content of a directory
823778under some path in your web API. As mentioned earlier in this document, the
824779`Raw` combinator can be used in your APIs to mean "plug here any WAI
825−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
826781directory serving WAI application, namely:
827782
828783``` haskell ignore
829784-- exported by Servant and Servant.Server
830−serveDirectory :: FilePath -> Server Raw
785+serveDirectoryWebApp :: FilePath -> Server Raw
831786```
832787
833−`serveDirectory`'s argument must be a path to a valid directory. You can see an
834−example below, runnable with `dist/build/tutorial/tutorial 6`
835−(you **must** run it from within the *servant-examples/* directory!), which is
836−a webserver that serves the various bits of code covered in this
837−getting-started.
788+`serveDirectoryWebApp`'s argument must be a path to a valid directory.
838789
839−The API type will be the following.
790+Here's an example API that will serve some static files:
840791
841792``` haskell
842−type CodeAPI = "code" :> Raw
793+type StaticAPI = "static" :> Raw
843794```
844795
845796And the server:
846797
847798``` haskell
848−codeAPI :: Proxy CodeAPI
849−codeAPI = Proxy
799+staticAPI :: Proxy StaticAPI
800+staticAPI = Proxy
850801```
851802
852803``` haskell
853−server7 :: Server CodeAPI
854−server7 = serveDirectory "tutorial"
804+server7 :: Server StaticAPI
805+server7 = serveDirectoryWebApp "static-files"
855806
856807app3 :: Application
857−app3 = serve codeAPI server7
808+app3 = serve staticAPI server7
858809```
859810
860−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.
861−
862−In other words:
863−
864−- If a client requests `/code/foo.txt`, the server will look for a file at `./tutorial/foo.txt` (and fail)
865−- If a client requests `/code/T1.hs`, the server will look for a file at `./tutorial/T1.hs` (and succeed)
866−- 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)
867−
868−Here is our little server in action.
869−
870−``` haskell ignore
871−$ curl http://localhost:8081/code/T1.hs
872−{-# LANGUAGE DataKinds #-}
873−{-# LANGUAGE TypeFamilies #-}
874−{-# LANGUAGE DeriveGeneric #-}
875−{-# LANGUAGE TypeOperators #-}
876−module T1 where
877−
878−import Data.Aeson
879−import Data.Time.Calendar
880−import GHC.Generics
881−import Network.Wai
882−import Servant
883−
884−data User = User
885− { name :: String
886− , age :: Int
887− , email :: String
888− , registration_date :: Day
889− } deriving (Eq, Show, Generic)
890−
891−-- orphan ToJSON instance for Day. necessary to derive one for User
892−instance ToJSON Day where
893− -- display a day in YYYY-mm-dd format
894− toJSON d = toJSON (showGregorian d)
895−
896−instance ToJSON User
897−
898−type UserAPI = "users" :> Get '[JSON] [User]
899−
900−users :: [User]
901−users =
902− [ User "Isaac Newton" 372 "isaac@newton.co.uk" (fromGregorian 1683 3 1)
903− , User "Albert Einstein" 136 "ae@mc2.org" (fromGregorian 1905 12 1)
904− ]
905−
906−userAPI :: Proxy UserAPI
907−userAPI = Proxy
908−
909−server :: Server UserAPI
910−server = return users
911−
912−app :: Application
913−app = serve userAPI server
914−$ curl http://localhost:8081/code/tutorial.hs
915−import Network.Wai
916−import Network.Wai.Handler.Warp
917−import System.Environment
918−
919−import qualified T1
920−import qualified T2
921−import qualified T3
922−import qualified T4
923−import qualified T5
924−import qualified T6
925−import qualified T7
926−import qualified T9
927−import qualified T10
928−
929−app :: String -> (Application -> IO ()) -> IO ()
930−app n f = case n of
931− "1" -> f T1.app
932− "2" -> f T2.app
933− "3" -> f T3.app
934− "4" -> f T4.app
935− "5" -> f T5.app
936− "6" -> f T6.app
937− "7" -> f T7.app
938− "8" -> f T3.app
939− "9" -> T9.writeJSFiles >> f T9.app
940− "10" -> f T10.app
941− _ -> usage
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.
942814
943−main :: IO ()
944−main = do
945− args <- getArgs
946− case args of
947− [n] -> app n (run 8081)
948− _ -> usage
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.
949818
950−usage :: IO ()
951−usage = do
952− putStrLn "Usage:\t tutorial N"
953− putStrLn "\t\twhere N is the number of the example you want to run."
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.
954822
955−$ curl http://localhost:8081/foo
956−not found
957−```
823+## Nested APIs
958824
959−Nested APIs
960−===========
961−
962−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:
963827
964828``` haskell
965829type UserAPI3 = -- view the user with given userid, in JSON
966830 Capture "userid" Int :> Get '[JSON] User
967831
968832 :<|> -- delete the user with given userid. empty response
969− Capture "userid" Int :> Delete '[] ()
833+ Capture "userid" Int :> DeleteNoContent
970834```
971835
972836We can instead factor out the `userid`:
@@ -974,32 +838,34 @@ We can instead factor out the `userid`:
974838``` haskell
975839type UserAPI4 = Capture "userid" Int :>
976840 ( Get '[JSON] User
977− :<|> Delete '[] ()
841+ :<|> DeleteNoContent
978842 )
979843```
980844
981−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`:
982847
983848``` haskell ignore
984−Server UserAPI3 = (Int -> EitherT ServantErr IO User)
985− :<|> (Int -> EitherT ServantErr IO ())
849+Server UserAPI3 = (Int -> Handler User)
850+ :<|> (Int -> Handler NoContent)
986851
987−Server UserAPI4 = Int -> ( EitherT ServantErr IO User
988− :<|> EitherT ServantErr IO ()
852+Server UserAPI4 = Int -> ( Handler User
853+ :<|> Handler NoContent
989854 )
990855```
991856
992857In the first case, each handler receives the *userid* argument. In the latter,
993−the whole `Server` takes the *userid* and has handlers that are just computations in `EitherT`, 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:
994860
995861``` haskell
996862server8 :: Server UserAPI3
997863server8 = getUser :<|> deleteUser
998864
999− where getUser :: Int -> EitherT ServantErr IO User
865+ where getUser :: Int -> Handler User
1000866 getUser _userid = error "..."
1001867
1002− deleteUser :: Int -> EitherT ServantErr IO ()
868+ deleteUser :: Int -> Handler NoContent
1003869 deleteUser _userid = error "..."
1004870
1005871-- notice how getUser and deleteUser
@@ -1008,14 +874,17 @@ server8 = getUser :<|> deleteUser
1008874server9 :: Server UserAPI4
1009875server9 userid = getUser userid :<|> deleteUser userid
1010876
1011− where getUser :: Int -> EitherT ServantErr IO User
877+ where getUser :: Int -> Handler User
1012878 getUser = error "..."
1013879
1014− deleteUser :: Int -> EitherT ServantErr IO ()
880+ deleteUser :: Int -> Handler NoContent
1015881 deleteUser = error "..."
1016882```
1017883
1018−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`.
1019888
1020889``` haskell
1021890-- we just factor out the "users" path fragment
@@ -1027,62 +896,63 @@ type API1 = "users" :>
1027896-- we factor out the Request Body
1028897type API2 = ReqBody '[JSON] User :>
1029898 ( Get '[JSON] User -- just display the same user back, don't register it
1030− :<|> Post '[JSON] () -- register the user. empty response
899+ :<|> PostNoContent -- register the user. empty response
1031900 )
1032901
1033902-- we factor out a Header
1034903type API3 = Header "Authorization" Token :>
1035904 ( Get '[JSON] SecretData -- get some secret data, if authorized
1036− :<|> ReqBody '[JSON] SecretData :> Post '[] () -- add some secret data, if authorized
905+ :<|> ReqBody '[JSON] SecretData :> PostNoContent -- add some secret data, if authorized
1037906 )
1038907
1039908newtype Token = Token ByteString
1040909newtype SecretData = SecretData ByteString
1041910```
1042911
1043−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.
1044914
1045915``` haskell
1046916type UsersAPI =
1047917 Get '[JSON] [User] -- list users
1048− :<|> ReqBody '[JSON] User :> Post '[] () -- add a user
918+ :<|> ReqBody '[JSON] User :> PostNoContent -- add a user
1049919 :<|> Capture "userid" Int :>
1050920 ( Get '[JSON] User -- view a user
1051− :<|> ReqBody '[JSON] User :> Put '[] () -- update a user
1052− :<|> Delete '[] () -- delete a user
921+ :<|> ReqBody '[JSON] User :> PutNoContent -- update a user
922+ :<|> DeleteNoContent -- delete a user
1053923 )
1054924
1055925usersServer :: Server UsersAPI
1056926usersServer = getUsers :<|> newUser :<|> userOperations
1057927
1058− where getUsers :: EitherT ServantErr IO [User]
928+ where getUsers :: Handler [User]
1059929 getUsers = error "..."
1060930
1061− newUser :: User -> EitherT ServantErr IO ()
931+ newUser :: User -> Handler NoContent
1062932 newUser = error "..."
1063933
1064934 userOperations userid =
1065935 viewUser userid :<|> updateUser userid :<|> deleteUser userid
1066936
1067937 where
1068− viewUser :: Int -> EitherT ServantErr IO User
938+ viewUser :: Int -> Handler User
1069939 viewUser = error "..."
1070940
1071− updateUser :: Int -> User -> EitherT ServantErr IO ()
941+ updateUser :: Int -> User -> Handler NoContent
1072942 updateUser = error "..."
1073943
1074− deleteUser :: Int -> EitherT ServantErr IO ()
944+ deleteUser :: Int -> Handler NoContent
1075945 deleteUser = error "..."
1076946```
1077947
1078948``` haskell
1079949type ProductsAPI =
1080950 Get '[JSON] [Product] -- list products
1081− :<|> ReqBody '[JSON] Product :> Post '[] () -- add a product
951+ :<|> ReqBody '[JSON] Product :> PostNoContent -- add a product
1082952 :<|> Capture "productid" Int :>
1083953 ( Get '[JSON] Product -- view a product
1084− :<|> ReqBody '[JSON] Product :> Put '[] () -- update a product
1085− :<|> Delete '[] () -- delete a product
954+ :<|> ReqBody '[JSON] Product :> PutNoContent -- update a product
955+ :<|> DeleteNoContent -- delete a product
1086956 )
1087957
1088958data Product = Product { productId :: Int }
@@ -1090,23 +960,23 @@ data Product = Product { productId :: Int }
1090960productsServer :: Server ProductsAPI
1091961productsServer = getProducts :<|> newProduct :<|> productOperations
1092962
1093− where getProducts :: EitherT ServantErr IO [Product]
963+ where getProducts :: Handler [Product]
1094964 getProducts = error "..."
1095965
1096− newProduct :: Product -> EitherT ServantErr IO ()
966+ newProduct :: Product -> Handler NoContent
1097967 newProduct = error "..."
1098968
1099969 productOperations productid =
1100970 viewProduct productid :<|> updateProduct productid :<|> deleteProduct productid
1101971
1102972 where
1103− viewProduct :: Int -> EitherT ServantErr IO Product
973+ viewProduct :: Int -> Handler Product
1104974 viewProduct = error "..."
1105975
1106− updateProduct :: Int -> Product -> EitherT ServantErr IO ()
976+ updateProduct :: Int -> Product -> Handler NoContent
1107977 updateProduct = error "..."
1108978
1109− deleteProduct :: Int -> EitherT ServantErr IO ()
979+ deleteProduct :: Int -> Handler NoContent
1110980 deleteProduct = error "..."
1111981```
1112982
@@ -1118,139 +988,213 @@ server10 :: Server CombinedAPI
1118988server10 = usersServer :<|> productsServer
1119989```
1120990
1121−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:
1122993
1123994``` haskell
1124995-- API for values of type 'a'
1125996-- indexed by values of type 'i'
1126997type APIFor a i =
1127998 Get '[JSON] [a] -- list 'a's
1128− :<|> ReqBody '[JSON] a :> Post '[] () -- add an 'a'
999+ :<|> ReqBody '[JSON] a :> PostNoContent -- add an 'a'
11291000 :<|> Capture "id" i :>
11301001 ( Get '[JSON] a -- view an 'a' given its "identifier" of type 'i'
1131− :<|> ReqBody '[JSON] a :> Put '[] () -- update an 'a'
1132− :<|> Delete '[] () -- delete an 'a'
1002+ :<|> ReqBody '[JSON] a :> PutNoContent -- update an 'a'
1003+ :<|> DeleteNoContent -- delete an 'a'
11331004 )
11341005
11351006-- Build the appropriate 'Server'
11361007-- given the handlers of the right type.
1137−serverFor :: EitherT ServantErr IO [a] -- handler for listing of 'a's
1138− -> (a -> EitherT ServantErr IO ()) -- handler for adding an 'a'
1139− -> (i -> EitherT ServantErr IO a) -- handler for viewing an 'a' given its identifier of type 'i'
1140− -> (i -> a -> EitherT ServantErr IO ()) -- updating an 'a' with given id
1141− -> (i -> EitherT 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
11421013 -> Server (APIFor a i)
11431014serverFor = error "..."
11441015-- implementation left as an exercise. contact us on IRC
11451016-- or the mailing list if you get stuck!
11461017```
11471018
1148−Using another monad for your handlers
1149−=====================================
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:
11501022
1151−Remember how `Server` turns combinators for HTTP methods into `EitherT 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.
11521034
11531035``` haskell ignore
1154−type Server api = ServerT api (EitherT ServantErr IO)
1036+type Server api = ServerT api Handler
11551037```
11561038
1157−`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`.
11581046
1159−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?
11601050
1161−Natural transformations
1162−-----------------------
1051+### Natural transformations
11631052
11641053If we have a function that gets us from an `m a` to an `n a`, for any `a`, what
11651054do we have?
11661055
1167−``` haskell ignore
1168−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:
11691061
1170−-- For example
1171−-- listToMaybeNat ::`[] :~> Maybe`
1172−-- listToMaybeNat = Nat listToMaybe -- from Data.Maybe
1062+``` haskell
1063+listToMaybe' :: [] ~> Maybe
1064+listToMaybe' = listToMaybe -- from Data.Maybe
11731065```
1174−(`Nat` comes from "natural transformation", in case you're wondering.)
11751066
1176−So if you want to write handlers using another monad/type than `EitherT
1177−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
11781071prepare is a function:
11791072
11801073``` haskell ignore
1181−readerToEither :: Reader String :~> EitherT ServantErr IO
1074+readerToHandler :: Reader String a -> Handler a
11821075```
11831076
1184−Let's start with `readerToEither'`. We obviously have to run the `Reader`
1185−computation by supplying it with a `String`, like `"hi"`. We get an `a` out
1186−from that and can then just `return` it into `EitherT`. We can then just wrap
1187−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`.
11881080
11891081``` haskell
1190−readerToEither' :: forall a. Reader String a -> EitherT ServantErr IO a
1191−readerToEither' r = return (runReader r "hi")
1192−
1193−readerToEither :: Reader String :~> EitherT ServantErr IO
1194−readerToEither = Nat readerToEither'
1082+readerToHandler :: Reader String a -> Handler a
1083+readerToHandler r = return (runReader r "hi")
11951084```
11961085
11971086We can write some simple webservice with the handlers running in `Reader String`.
11981087
11991088``` haskell
12001089type ReaderAPI = "a" :> Get '[JSON] Int
1201− :<|> "b" :> Get '[JSON] String
1090+ :<|> "b" :> ReqBody '[JSON] Double :> Get '[JSON] Bool
12021091
12031092readerAPI :: Proxy ReaderAPI
12041093readerAPI = Proxy
12051094
12061095readerServerT :: ServerT ReaderAPI (Reader String)
1207−readerServerT = a :<|> b
1208−
1209− where a :: Reader String Int
1210− a = return 1797
1096+readerServerT = a :<|> b where
1097+ a :: Reader String Int
1098+ a = return 1797
12111099
1212− b :: Reader String String
1213− b = ask
1100+ b :: Double -> Reader String Bool
1101+ b _ = asks (== "hi")
12141102```
12151103
12161104We unfortunately can't use `readerServerT` as an argument of `serve`, because
1217−`serve` wants a `Server ReaderAPI`, i.e., with handlers running in `EitherT
1218−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.
12191106
1220−Enter `enter`
1221−-------------
1107+### Welcome `hoistServer`
12221108
1223−That's right. We have just written `readerToEither`, which is exactly what we
1224−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
12251111right type for `serve`. Being cumbersome to do by hand, we provide a function
1226−`enter` which takes a natural transformation between two parametrized types `m`
1112+`hoistServer` which takes a natural transformation between two parameterized types `m`
12271113and `n` and a `ServerT someapi m`, and returns a `ServerT someapi n`.
12281114
1229−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.
12301117
12311118``` haskell
12321119readerServer :: Server ReaderAPI
1233−readerServer = enter readerToEither readerServerT
1120+readerServer = hoistServer readerAPI readerToHandler readerServerT
12341121
12351122app4 :: Application
12361123app4 = serve readerAPI readerServer
12371124```
12381125
1239−And we can indeed see this webservice in action by running `dist/build/tutorial/tutorial 7`.
1126+This is the webservice in action:
12401127
12411128``` bash
12421129$ curl http://localhost:8081/a
124311301797
1244−$ curl http://localhost:8081/b
1245−"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)
12461185```
12471186
1248−Conclusion
1249−==========
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.
12501195
1251−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
12521197
1253−<div style="text-align: center;">
1254− <p><a href="/tutorial/api-type.html">Previous page: A web API as a type</a></p>
1255− <p><a href="/tutorial/client.html">Next page: Deriving Haskell functions to query an API</a></p>
1256−</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**.