@@ -3,29 +3,10 @@
33Enough chit-chat about type-level combinators and representing an API as a
44type. Can we have a webservice already?
55
6−If you want to follow along with the code and run the examples while you read this guide:
7−
8−``` bash
9−cabal get servant-examples
10−cd servant-examples-<VERSION>
11−cabal sandbox init
12−cabal install --dependencies-only
13−cabal configure && cabal build
14−```
15−
16−This will produce a `tutorial` executable in the
17−`dist/build/tutorial` directory that just runs the example corresponding
18−to the number specified as a command line argument:
19−
20−``` bash
21−$ dist/build/tutorial/tutorial
22−Usage: tutorial N
23− where N is the number of the example you want to run.
24−```
25−
266## A first example
277
28−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.
2910
3011The source for this tutorial section is a literate haskell file, so first we
3112need to have some language extensions and imports:
@@ -37,6 +18,7 @@ need to have some language extensions and imports:
3718{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3819{-# LANGUAGE MultiParamTypeClasses #-}
3920{-# LANGUAGE OverloadedStrings #-}
21+{-# LANGUAGE RankNTypes #-}
4022{-# LANGUAGE ScopedTypeVariables #-}
4123{-# LANGUAGE TypeOperators #-}
4224
@@ -45,14 +27,14 @@ module Server where
4527import Prelude ()
4628import Prelude.Compat
4729
48−import Control.Monad.IO.Class
30+import Control.Monad.Except
4931import Control.Monad.Reader
50−import Control.Monad.Trans.Except
5132import Data.Aeson
5233import Data.Aeson.Types
5334import Data.Attoparsec.ByteString
5435import Data.ByteString (ByteString)
5536import Data.List
37+import Data.Maybe
5638import Data.String.Conversions
5739import Data.Time.Calendar
5840import GHC.Generics
@@ -64,15 +46,18 @@ import Servant
6446import System.Directory
6547import Text.Blaze
6648import Text.Blaze.Html.Renderer.Utf8
49+import Servant.Types.SourceT (source)
6750import qualified Data.Aeson.Parser
6851import qualified Text.Blaze.Html
6952```
7053
71−``` haskell ignore
72−{-# LANGUAGE TypeFamilies #-}
73−```
74−
75−**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.
7661
7762We will write a server that will serve the following API.
7863
@@ -95,7 +80,7 @@ data User = User
9580 { name :: String
9681 , age :: Int
9782 , email :: String
98− , registrationDate :: Day
83+ , registration_date :: Day
9984 } deriving (Eq, Show, Generic)
10085
10186instance ToJSON User
@@ -111,12 +96,6 @@ users1 =
11196 ]
11297```
11398
114−Let's also write our API type.
115−
116−``` haskell ignore
117−type UserAPI1 = "users" :> Get '[JSON] [User]
118−```
119−
12099We can now take care of writing the actual webservice that will handle requests
121100to such an API. This one will be very simple, being reduced to just a single
122101endpoint. The type of the web application is determined by the API type,
@@ -128,11 +107,11 @@ corresponding API type.
128107The first thing to know about the `Server` type family is that behind the
129108scenes it will drive the routing, letting you focus only on the business
130109logic. The second thing to know is that for each endpoint, your handlers will
131−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
132111easily, as explained near the end of this guide. Third thing, the type of the
133112value returned in that monad must be the same as the second argument of the
134113HTTP method combinator used for the corresponding endpoint. In our case, it
135−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,
136115we have a monad, let's just `return` our list:
137116
138117``` haskell
@@ -140,7 +119,9 @@ server1 :: Server UserAPI1
140119server1 = return users1
141120```
142121
143−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):
144125
145126``` haskell
146127userAPI :: Proxy UserAPI1
@@ -150,7 +131,7 @@ userAPI = Proxy
150131-- which you can think of as an "abstract" web application,
151132-- not yet a webserver.
152133app1 :: Application
153−app1 = serve userAPI EmptyConfig server1
134+app1 = serve userAPI server1
154135```
155136
156137The `userAPI` bit is, alas, boilerplate (we need it to guide type inference).
@@ -165,9 +146,8 @@ main = run 8081 app1
165146
166147You can put this all into a file or just grab [servant's
167148repo](http://github.com/haskell-servant/servant) and look at the
168−*servant-examples* directory. The code we have just explored is in
169−*tutorial/T1.hs*, runnable with
170−`dist/build/tutorial/tutorial 1`.
149+*doc/tutorial* directory. This code (the source of this web page) is in
150+*doc/tutorial/Server.lhs*.
171151
172152If you run it, you can go to `http://localhost:8081/users` in your browser or
173153query it with curl and you see:
@@ -179,7 +159,8 @@ $ curl http://localhost:8081/users
179159
180160## More endpoints
181161
182−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.
183164
184165``` haskell
185166type UserAPI2 = "users" :> Get '[JSON] [User]
@@ -202,7 +183,7 @@ users2 = [isaac, albert]
202183
203184Now, just like we separate the various endpoints in `UserAPI` with `:<|>`, we
204185are going to separate the handlers with `:<|>` too! They must be provided in
205−the same order as the one they appear in in the API type.
186+the same order as in the API type.
206187
207188``` haskell
208189server2 :: Server UserAPI2
@@ -211,21 +192,21 @@ server2 = return users2
211192 :<|> return isaac
212193```
213194
214−And that's it! You can run this example with
215−`dist/build/tutorial/tutorial 2` and check out the data available
216−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`.
217197
218198## From combinators to handler arguments
219199
220200Fine, we can write trivial webservices easily, but none of the two above use
221201any "fancy" combinator from servant. Let's address this and use `QueryParam`,
222−`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
223203combinators in an endpoint makes the corresponding handler receive an
224204argument of the appropriate type automatically. You don't have to worry about
225205manually looking up URL captures or query string parameters, or
226206decoding/encoding data from/to JSON. Never.
227207
228−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`.
229210
230211``` haskell
231212type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
@@ -284,15 +265,15 @@ server3 = position
284265 :<|> hello
285266 :<|> marketing
286267
287− where position :: Int -> Int -> ExceptT ServantErr IO Position
268+ where position :: Int -> Int -> Handler Position
288269 position x y = return (Position x y)
289270
290− hello :: Maybe String -> ExceptT ServantErr IO HelloMessage
271+ hello :: Maybe String -> Handler HelloMessage
291272 hello mname = return . HelloMessage $ case mname of
292273 Nothing -> "Hello, anonymous coward"
293274 Just n -> "Hello, " ++ n
294275
295− marketing :: ClientInfo -> ExceptT ServantErr IO Email
276+ marketing :: ClientInfo -> Handler Email
296277 marketing clientinfo = return (emailForClient clientinfo)
297278```
298279
@@ -307,41 +288,40 @@ parameter might not always be there);
307288
308289 - a `ReqBody contentTypeList a` becomes an argument of type `a`;
309290
310−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:
311292
312293``` bash
313294$ curl http://localhost:8081/position/1/2
314−{"x":1,"y":2}
295+{"xCoord":1,"yCoord":2}
315296$ curl http://localhost:8081/hello
316297{"msg":"Hello, anonymous coward"}
317298$ curl http://localhost:8081/hello?name=Alp
318299{"msg":"Hello, Alp"}
319−$ 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
320301{"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"}
321302```
322303
323−For reference, here's a list of some combinators from *servant* and for those
324−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**:
325305
326− > - `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>`.
327307 > - `Capture "something" a` becomes an argument of type `a`.
328− > - `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.
329− > - `QueryFlag "something"` and `MatrixFlag "something"` get turned into arguments of type `Bool`.
330− > - `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]`.
331311 > - `ReqBody contentTypes a` gets turned into an argument of type `a`.
332312
333313## The `FromHttpApiData`/`ToHttpApiData` classes
334314
335−Wait... How does *servant* know how to decode the `Int`s from the URL? Or how
336−to decode a `ClientInfo` value from the request body? This is what this and the
337−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.
338318
339319`Capture`s and `QueryParam`s are represented by some textual value in URLs.
340320`Header`s are similarly represented by a pair of a header name and a
341321corresponding (textual) value in the request's "metadata". How types are
342322decoded from headers, captures, and query params is expressed in a class
343323`FromHttpApiData` (from the package
344−[*http-api-data*](http://hackage.haskell.org/package/http-api-data)):
324+[**http-api-data**](http://hackage.haskell.org/package/http-api-data)):
345325
346326``` haskell ignore
347327class FromHttpApiData a where
@@ -363,15 +343,15 @@ As you can see, as long as you provide either `parseUrlPiece` (for `Capture`s)
363343or `parseQueryParam` (for `QueryParam`s), the other methods will be defined in
364344terms of this.
365345
366−*http-api-data* provides a decent number of instances, helpers for defining new
346+**http-api-data** provides a decent number of instances, helpers for defining new
367347ones, and wonderful documentation.
368348
369349There's not much else to say about these classes. You will need instances for
370350them when using `Capture`, `QueryParam`, `QueryParams`, and `Header` with your
371351types. You will need `FromHttpApiData` instances for server-side request
372352handlers and `ToHttpApiData` instances only when using
373−*servant-client*, as described in the [section about deriving haskell
374−functions to query an API](/tutorial/client.html).
353+**servant-client**, as described in the [section about deriving haskell
354+functions to query an API](Client.html).
375355
376356## Using content-types with your data types
377357
@@ -379,14 +359,15 @@ The same principle was operating when decoding request bodies from JSON, and
379359responses *into* JSON. (JSON is just the running example - you can do this with
380360any content-type.)
381361
382−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
383363all of this work.
384364
385365### The truth behind `JSON`
386366
387367
388−What exactly is `JSON`? Like the 3 other content types provided out of the box
389−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.
390371
391372``` haskell ignore
392373data JSON
@@ -396,14 +377,15 @@ data OctetStream
396377```
397378
398379Obviously, this is not all there is to `JSON`, otherwise it would be quite
399−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
400381a special *symbol* that's associated with encoding (resp. decoding) to (resp.
401382from) the *JSON* format. The way this association is performed can be
402383decomposed into two steps.
403384
404385The first step is to provide a proper
405−[`MediaType`](https://hackage.haskell.org/package/http-media-0.6.2/docs/Network-HTTP-Media.html)
406−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
407389haddocks from this link, you can see that we just have to specify
408390`application/json` using the appropriate functions. In our case, we can just
409391use `(//) :: ByteString -> ByteString -> MediaType`. The precise way to specify
@@ -419,14 +401,14 @@ instance Accept JSON where
419401```
420402
421403The second step is centered around the `MimeRender` and `MimeUnrender` classes.
422−These classes just let you specify a way to respectively encode and decode
423−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.
424406
425407``` haskell ignore
426408class Accept ctype => MimeRender ctype a where
427− mimeRender :: Proxy ctype -> a -> ByteString
409+ mimeRender :: Proxy ctype -> a -> ByteString
428410 -- alternatively readable as:
429− mimeRender :: Proxy ctype -> (a -> ByteString)
411+ mimeRender :: Proxy ctype -> (a -> ByteString)
430412```
431413
432414Given a content-type and some user type, `MimeRender` provides a function that
@@ -452,7 +434,7 @@ class Accept ctype => MimeUnrender ctype a where
452434We don't have much work to do there either, `Data.Aeson.eitherDecode` is
453435precisely what we need. However, it only allows arrays and objects as toplevel
454436JSON values and this has proven to get in our way more than help us so we wrote
455−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
456438JSON value at the toplevel of a "JSON document". Here's the definition in case
457439you are curious.
458440
@@ -470,20 +452,20 @@ instance FromJSON a => MimeUnrender JSON a where
470452 mimeUnrender _ = eitherDecodeLenient
471453```
472454
473−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`,
474456`Post` and friends. We can check our understanding by implementing support
475−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
476458HTML representation of the data they want, ready to be included in any HTML
477−document, e.g. using [jQuery's `load` function](https://api.jquery.com/load/), simply by adding `Accept:
478−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.
479461
480−### Case-studies: *servant-blaze* and *servant-lucid*
462+### Case-studies: **servant-blaze** and **servant-lucid**
481463
482464These days, most of the haskellers who write their HTML UIs directly from
483−Haskell use either [blaze-html](http://hackage.haskell.org/package/blaze-html)
484−or [lucid](http://hackage.haskell.org/package/lucid). The best option for
485−*servant* is obviously to support both (and hopefully other templating
486−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**:
487469
488470``` haskell
489471data HTMLLucid
@@ -491,24 +473,20 @@ data HTMLLucid
491473
492474Once again, the data type is just there as a symbol for the encoding/decoding
493475functions, except that this time we will only worry about encoding since
494−*blaze-html* and *lucid* don't provide a way to extract data from HTML.
495−
496−Both packages also have the same `Accept` instance for their `HTMLLucid` type.
476+**lucid** doesn't provide a way to extract data from HTML.
497477
498478``` haskell
499479instance Accept HTMLLucid where
500480 contentType _ = "text" // "html" /: ("charset", "utf-8")
501481```
502482
503−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
504484us specify additional information about a content-type, like the charset here.
505485
506−The rendering instances for both packages both call similar functions that take
486+The rendering instances call similar functions that take
507487types with an appropriate instance to an "abstract" HTML representation and
508488then write that to a `ByteString`.
509489
510−For *lucid*:
511−
512490``` haskell
513491instance ToHtml a => MimeRender HTMLLucid a where
514492 mimeRender _ = renderBS . toHtml
@@ -519,7 +497,7 @@ instance MimeRender HTMLLucid (Html a) where
519497 mimeRender _ = renderBS
520498```
521499
522−For *blaze-html*:
500+For **blaze-html** everything works very similarly:
523501
524502``` haskell
525503-- For this tutorial to compile 'HTMLLucid' and 'HTMLBlaze' have to be
@@ -539,15 +517,13 @@ instance MimeRender HTMLBlaze Text.Blaze.Html.Html where
539517 mimeRender _ = renderHtml
540518```
541519
542−Both [servant-blaze](http://hackage.haskell.org/package/servant-blaze) and
543−[servant-lucid](http://hackage.haskell.org/package/servant-lucid) let you use
544−`HTMLLucid` in any content type list as long as you provide an instance of the
545−appropriate class (`ToMarkup` for *blaze-html*, `ToHtml` for *lucid*).
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**).
546524
547−We can now write webservice that uses *servant-lucid* to show the `HTMLLucid`
548−content type in action. First off, imports and pragmas as usual.
549−
550−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:
551527
552528``` haskell
553529type PersonAPI = "persons" :> Get '[JSON, HTMLLucid] [Person]
@@ -564,7 +540,7 @@ data Person = Person
564540instance ToJSON Person
565541```
566542
567−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
568544a list of `Person`s as a table with a row per person.
569545
570546``` haskell
@@ -608,48 +584,45 @@ server4 :: Server PersonAPI
608584server4 = return people
609585
610586app2 :: Application
611−app2 = serve personAPI EmptyConfig server4
587+app2 = serve personAPI server4
612588```
613589
614−And we're good to go. You can run this example with `dist/build/tutorial/tutorial 4`.
590+And we're good to go:
615591
616592``` bash
617− $ curl http://localhost:8081/persons
618− [{"lastName":"Newton","firstName":"Isaac"},{"lastName":"Einstein","firstName":"Albert"}]
619− $ curl -H 'Accept: text/html' http://localhost:8081/persons
620− <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>
621− # 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
622598```
623599
624−## The `ExceptT ServantErr IO` monad
600+## The `Handler` monad
625601
626−At the heart of the handlers is the monad they run in, namely `ExceptT
627−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
628605simplest monad with the following properties:
629606
630−- it lets us both return a successful result (with the `Right` branch of
631−`Either`) or "fail" with a descriptive error (with the `Left` branch of
632−`Either`);
607+- it lets us both return a successful result (using `return`)
608+or "fail" with a descriptive error (using `throwError`);
633609- it lets us perform IO, which is absolutely vital since most webservices exist
634−as interfaces to databases that we interact with in `IO`;
610+as interfaces to databases that we interact with in `IO`.
635611
636612Let's recall some definitions.
637613
638614``` haskell ignore
639−-- from the Prelude
640−data Either e a = Left e | Right a
641−
642615-- from the 'mtl' package at
643−newtype ExceptT e m a = ExceptT ( m (Either e a) )
616+newtype ExceptT e m a = ExceptT (m (Either e a))
644617```
645618
646−In short, this means that a handler of type `ExceptT ServantErr IO a` is simply
647−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
648621action that either returns an error or a result.
649622
650−The module [`Control.Monad.Except`](https://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#t:ExceptT)
623+The module [`Control.Monad.Except`](https://hackage.haskell.org/package/mtl/docs/Control-Monad-Except.html#t:ExceptT)
651624from which `ExceptT` comes is worth looking at.
652−Perhaps most importantly, `ExceptT` is an instance of `MonadError`, so
625+Perhaps most importantly, `ExceptT` and `Handler` are instances of `MonadError`, so
653626`throwError` can be used to return an error from your handler (whereas `return`
654627 is enough to return a success).
655628
@@ -659,18 +632,17 @@ kind and abort early. The next two sections cover how to do just that.
659632
660633### Performing IO
661634
662−Another important instance from the list above is `MonadIO m => MonadIO
663−(ExceptT e m)`.
664−[`MonadIO`](http://hackage.haskell.org/package/transformers-0.4.3.0/docs/Control-Monad-IO-Class.html)
665−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:
666639
667640``` haskell ignore
668641class Monad m => MonadIO m where
669642 liftIO :: IO a -> m a
670643```
671644
672−Obviously, the `IO` monad provides a `MonadIO` instance. Hence for any type
673−`e`, `ExceptT e IO` has a `MonadIO` instance. So if you want to run any kind of
645+So if you want to run any kind of
674646IO computation in your handlers, just use `liftIO`:
675647
676648``` haskell
@@ -688,16 +660,16 @@ server5 = do
688660 return (FileContent filecontent)
689661```
690662
691−### Failing, through `ServantErr`
663+### Failing, through `ServerError`
692664
693665If you want to explicitly fail at providing the result promised by an endpoint
694666using the appropriate HTTP status code (not found, unauthorized, etc) and some
695−error message, all you have to do is use the `left` function mentioned above
696−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
697669defined as:
698670
699671``` haskell ignore
700−data ServantErr = ServantErr
672+data ServerError = ServerError
701673 { errHTTPCode :: Int
702674 , errReasonPhrase :: String
703675 , errBody :: ByteString -- lazy bytestring
@@ -710,10 +682,10 @@ module. If you want to use these values but add a body or some headers, just
710682use record update syntax:
711683
712684``` haskell
713−failingHandler :: ExceptT ServantErr IO ()
714−failingHandler = throwE myerr
685+failingHandler :: Handler ()
686+failingHandler = throwError myerr
715687
716− where myerr :: ServantErr
688+ where myerr :: ServerError
717689 myerr = err503 { errBody = "Sorry dear user." }
718690```
719691
@@ -726,47 +698,47 @@ server6 = do
726698 exists <- liftIO (doesFileExist "myfile.txt")
727699 if exists
728700 then liftIO (readFile "myfile.txt") >>= return . FileContent
729− else throwE custom404Err
701+ else throwError custom404Err
730702
731703 where custom404Err = err404 { errBody = "myfile.txt just isn't there, please leave this server alone." }
732704```
733705
734−Let's run this server (`dist/build/tutorial/tutorial 5`) and
735−query it, first without the file and then with the file.
706+Here's how that server looks in action:
736707
737708``` bash
738− $ curl --verbose http://localhost:8081/myfile.txt
739− [snip]
740− * Connected to localhost (127.0.0.1) port 8081 (#0)
741− > GET /myfile.txt HTTP/1.1
742− > User-Agent: curl/7.30.0
743− > Host: localhost:8081
744− > Accept: */*
745− >
746− < HTTP/1.1 404 Not Found
747− [snip]
748− myfile.txt just isnt there, please leave this server alone.
749−
750− $ echo Hello > myfile.txt
751−
752− $ curl --verbose http://localhost:8081/myfile.txt
753− [snip]
754− * Connected to localhost (127.0.0.1) port 8081 (#0)
755− > GET /myfile.txt HTTP/1.1
756− > User-Agent: curl/7.30.0
757− > Host: localhost:8081
758− > Accept: */*
759− >
760− < HTTP/1.1 200 OK
761− [snip]
762− < Content-Type: application/json
763− [snip]
764− {"content":"Hello\n"}
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"}
765736```
766737
767738## Response headers
768739
769−To add headers to your response, use [addHeader](http://hackage.haskell.org/package/servant-0.4.4/docs/Servant-API-ResponseHeaders.html).
740+To add headers to your response, use
741+[addHeader](http://hackage.haskell.org/package/servant/docs/Servant-API-ResponseHeaders.html).
770742Note that this changes the type of your API, as we can see in the following example:
771743
772744``` haskell
@@ -776,159 +748,89 @@ myHandler :: Server MyHandler
776748myHandler = return $ addHeader 1797 albert
777749```
778750
779−Note that the type of `addHeader x` is different than the type of `x`!
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`:
765+
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+```
780774
781775## Serving static files
782776
783−*servant-server* also provides a way to just serve the content of a directory
777+**servant-server** also provides a way to just serve the content of a directory
784778under some path in your web API. As mentioned earlier in this document, the
785779`Raw` combinator can be used in your APIs to mean "plug here any WAI
786−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
787781directory serving WAI application, namely:
788782
789783``` haskell ignore
790784-- exported by Servant and Servant.Server
791−serveDirectory :: FilePath -> Server Raw
785+serveDirectoryWebApp :: FilePath -> Server Raw
792786```
793787
794−`serveDirectory`'s argument must be a path to a valid directory. You can see an
795−example below, runnable with `dist/build/tutorial/tutorial 6`
796−(you **must** run it from within the *servant-examples/* directory!), which is
797−a webserver that serves the various bits of code covered in this
798−getting-started.
788+`serveDirectoryWebApp`'s argument must be a path to a valid directory.
799789
800−The API type will be the following.
790+Here's an example API that will serve some static files:
801791
802792``` haskell
803−type CodeAPI = "code" :> Raw
793+type StaticAPI = "static" :> Raw
804794```
805795
806796And the server:
807797
808798``` haskell
809−codeAPI :: Proxy CodeAPI
810−codeAPI = Proxy
799+staticAPI :: Proxy StaticAPI
800+staticAPI = Proxy
811801```
812802
813803``` haskell
814−server7 :: Server CodeAPI
815−server7 = serveDirectory "tutorial"
804+server7 :: Server StaticAPI
805+server7 = serveDirectoryWebApp "static-files"
816806
817807app3 :: Application
818−app3 = serve codeAPI EmptyConfig server7
808+app3 = serve staticAPI server7
819809```
820810
821−This server will match any request whose path starts with `/code` and will look
811+This server will match any request whose path starts with `/static` and will look
822812for a file at the path described by the rest of the request path, inside the
823− *tutorial/* directory of the path you run the program from.
824−
825−In other words:
826−
827−- If a client requests `/code/foo.txt`, the server will look for a file at `./tutorial/foo.txt` (and fail)
828−- If a client requests `/code/T1.hs`, the server will look for a file at `./tutorial/T1.hs` (and succeed)
829−- 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)
830−
831−Here is our little server in action.
832−
833−``` haskell ignore
834−$ curl http://localhost:8081/code/T1.hs
835−{-# LANGUAGE DataKinds #-}
836−{-# LANGUAGE TypeFamilies #-}
837−{-# LANGUAGE DeriveGeneric #-}
838−{-# LANGUAGE TypeOperators #-}
839−module T1 where
813+ *static-files/* directory of the path you run the program from.
840814
841−import Data.Aeson
842−import Data.Time.Calendar
843−import GHC.Generics
844−import Network.Wai
845−import Servant
846−
847−data User = User
848− { name :: String
849− , age :: Int
850− , email :: String
851− , registration_date :: Day
852− } deriving (Eq, Show, Generic)
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.
853818
854−-- orphan ToJSON instance for Day. necessary to derive one for User
855−instance ToJSON Day where
856− -- display a day in YYYY-mm-dd format
857− toJSON d = toJSON (showGregorian d)
858−
859−instance ToJSON User
860−
861−type UserAPI = "users" :> Get '[JSON] [User]
862−
863−users :: [User]
864−users =
865− [ User "Isaac Newton" 372 "isaac@newton.co.uk" (fromGregorian 1683 3 1)
866− , User "Albert Einstein" 136 "ae@mc2.org" (fromGregorian 1905 12 1)
867− ]
868−
869−userAPI :: Proxy UserAPI
870−userAPI = Proxy
871−
872−server :: Server UserAPI
873−server = return users
874−
875−app :: Application
876−app = serve userAPI server
877−$ curl http://localhost:8081/code/tutorial.hs
878−import Network.Wai
879−import Network.Wai.Handler.Warp
880−import System.Environment
881−
882−import qualified T1
883−import qualified T2
884−import qualified T3
885−import qualified T4
886−import qualified T5
887−import qualified T6
888−import qualified T7
889−import qualified T9
890−import qualified T10
891−
892−app :: String -> (Application -> IO ()) -> IO ()
893−app n f = case n of
894− "1" -> f T1.app
895− "2" -> f T2.app
896− "3" -> f T3.app
897− "4" -> f T4.app
898− "5" -> f T5.app
899− "6" -> f T6.app
900− "7" -> f T7.app
901− "8" -> f T3.app
902− "9" -> T9.writeJSFiles >> f T9.app
903− "10" -> f T10.app
904− _ -> usage
905−
906−main :: IO ()
907−main = do
908− args <- getArgs
909− case args of
910− [n] -> app n (run 8081)
911− _ -> usage
912−
913−usage :: IO ()
914−usage = do
915− putStrLn "Usage:\t tutorial N"
916− putStrLn "\t\twhere N is the number of the example you want to run."
917−
918−$ curl http://localhost:8081/foo
919−not found
920−```
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.
921822
922823## Nested APIs
923824
924−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:
925827
926828``` haskell
927829type UserAPI3 = -- view the user with given userid, in JSON
928830 Capture "userid" Int :> Get '[JSON] User
929831
930832 :<|> -- delete the user with given userid. empty response
931− Capture "userid" Int :> Delete '[] ()
833+ Capture "userid" Int :> DeleteNoContent
932834```
933835
934836We can instead factor out the `userid`:
@@ -936,32 +838,34 @@ We can instead factor out the `userid`:
936838``` haskell
937839type UserAPI4 = Capture "userid" Int :>
938840 ( Get '[JSON] User
939− :<|> Delete '[] ()
841+ :<|> DeleteNoContent
940842 )
941843```
942844
943−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`:
944847
945848``` haskell ignore
946−Server UserAPI3 = (Int -> ExceptT ServantErr IO User)
947− :<|> (Int -> ExceptT ServantErr IO ())
849+Server UserAPI3 = (Int -> Handler User)
850+ :<|> (Int -> Handler NoContent)
948851
949−Server UserAPI4 = Int -> ( ExceptT ServantErr IO User
950− :<|> ExceptT ServantErr IO ()
852+Server UserAPI4 = Int -> ( Handler User
853+ :<|> Handler NoContent
951854 )
952855```
953856
954857In the first case, each handler receives the *userid* argument. In the latter,
955−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:
956860
957861``` haskell
958862server8 :: Server UserAPI3
959863server8 = getUser :<|> deleteUser
960864
961− where getUser :: Int -> ExceptT ServantErr IO User
865+ where getUser :: Int -> Handler User
962866 getUser _userid = error "..."
963867
964− deleteUser :: Int -> ExceptT ServantErr IO ()
868+ deleteUser :: Int -> Handler NoContent
965869 deleteUser _userid = error "..."
966870
967871-- notice how getUser and deleteUser
@@ -970,14 +874,17 @@ server8 = getUser :<|> deleteUser
970874server9 :: Server UserAPI4
971875server9 userid = getUser userid :<|> deleteUser userid
972876
973− where getUser :: Int -> ExceptT ServantErr IO User
877+ where getUser :: Int -> Handler User
974878 getUser = error "..."
975879
976− deleteUser :: Int -> ExceptT ServantErr IO ()
880+ deleteUser :: Int -> Handler NoContent
977881 deleteUser = error "..."
978882```
979883
980−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`.
981888
982889``` haskell
983890-- we just factor out the "users" path fragment
@@ -989,62 +896,63 @@ type API1 = "users" :>
989896-- we factor out the Request Body
990897type API2 = ReqBody '[JSON] User :>
991898 ( Get '[JSON] User -- just display the same user back, don't register it
992− :<|> Post '[JSON] () -- register the user. empty response
899+ :<|> PostNoContent -- register the user. empty response
993900 )
994901
995902-- we factor out a Header
996903type API3 = Header "Authorization" Token :>
997904 ( Get '[JSON] SecretData -- get some secret data, if authorized
998− :<|> ReqBody '[JSON] SecretData :> Post '[] () -- add some secret data, if authorized
905+ :<|> ReqBody '[JSON] SecretData :> PostNoContent -- add some secret data, if authorized
999906 )
1000907
1001908newtype Token = Token ByteString
1002909newtype SecretData = SecretData ByteString
1003910```
1004911
1005−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.
1006914
1007915``` haskell
1008916type UsersAPI =
1009917 Get '[JSON] [User] -- list users
1010− :<|> ReqBody '[JSON] User :> Post '[] () -- add a user
918+ :<|> ReqBody '[JSON] User :> PostNoContent -- add a user
1011919 :<|> Capture "userid" Int :>
1012920 ( Get '[JSON] User -- view a user
1013− :<|> ReqBody '[JSON] User :> Put '[] () -- update a user
1014− :<|> Delete '[] () -- delete a user
921+ :<|> ReqBody '[JSON] User :> PutNoContent -- update a user
922+ :<|> DeleteNoContent -- delete a user
1015923 )
1016924
1017925usersServer :: Server UsersAPI
1018926usersServer = getUsers :<|> newUser :<|> userOperations
1019927
1020− where getUsers :: ExceptT ServantErr IO [User]
928+ where getUsers :: Handler [User]
1021929 getUsers = error "..."
1022930
1023− newUser :: User -> ExceptT ServantErr IO ()
931+ newUser :: User -> Handler NoContent
1024932 newUser = error "..."
1025933
1026934 userOperations userid =
1027935 viewUser userid :<|> updateUser userid :<|> deleteUser userid
1028936
1029937 where
1030− viewUser :: Int -> ExceptT ServantErr IO User
938+ viewUser :: Int -> Handler User
1031939 viewUser = error "..."
1032940
1033− updateUser :: Int -> User -> ExceptT ServantErr IO ()
941+ updateUser :: Int -> User -> Handler NoContent
1034942 updateUser = error "..."
1035943
1036− deleteUser :: Int -> ExceptT ServantErr IO ()
944+ deleteUser :: Int -> Handler NoContent
1037945 deleteUser = error "..."
1038946```
1039947
1040948``` haskell
1041949type ProductsAPI =
1042950 Get '[JSON] [Product] -- list products
1043− :<|> ReqBody '[JSON] Product :> Post '[] () -- add a product
951+ :<|> ReqBody '[JSON] Product :> PostNoContent -- add a product
1044952 :<|> Capture "productid" Int :>
1045953 ( Get '[JSON] Product -- view a product
1046− :<|> ReqBody '[JSON] Product :> Put '[] () -- update a product
1047− :<|> Delete '[] () -- delete a product
954+ :<|> ReqBody '[JSON] Product :> PutNoContent -- update a product
955+ :<|> DeleteNoContent -- delete a product
1048956 )
1049957
1050958data Product = Product { productId :: Int }
@@ -1052,23 +960,23 @@ data Product = Product { productId :: Int }
1052960productsServer :: Server ProductsAPI
1053961productsServer = getProducts :<|> newProduct :<|> productOperations
1054962
1055− where getProducts :: ExceptT ServantErr IO [Product]
963+ where getProducts :: Handler [Product]
1056964 getProducts = error "..."
1057965
1058− newProduct :: Product -> ExceptT ServantErr IO ()
966+ newProduct :: Product -> Handler NoContent
1059967 newProduct = error "..."
1060968
1061969 productOperations productid =
1062970 viewProduct productid :<|> updateProduct productid :<|> deleteProduct productid
1063971
1064972 where
1065− viewProduct :: Int -> ExceptT ServantErr IO Product
973+ viewProduct :: Int -> Handler Product
1066974 viewProduct = error "..."
1067975
1068− updateProduct :: Int -> Product -> ExceptT ServantErr IO ()
976+ updateProduct :: Int -> Product -> Handler NoContent
1069977 updateProduct = error "..."
1070978
1071− deleteProduct :: Int -> ExceptT ServantErr IO ()
979+ deleteProduct :: Int -> Handler NoContent
1072980 deleteProduct = error "..."
1073981```
1074982
@@ -1080,135 +988,213 @@ server10 :: Server CombinedAPI
1080988server10 = usersServer :<|> productsServer
1081989```
1082990
1083−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:
1084993
1085994``` haskell
1086995-- API for values of type 'a'
1087996-- indexed by values of type 'i'
1088997type APIFor a i =
1089998 Get '[JSON] [a] -- list 'a's
1090− :<|> ReqBody '[JSON] a :> Post '[] () -- add an 'a'
999+ :<|> ReqBody '[JSON] a :> PostNoContent -- add an 'a'
10911000 :<|> Capture "id" i :>
10921001 ( Get '[JSON] a -- view an 'a' given its "identifier" of type 'i'
1093− :<|> ReqBody '[JSON] a :> Put '[] () -- update an 'a'
1094− :<|> Delete '[] () -- delete an 'a'
1002+ :<|> ReqBody '[JSON] a :> PutNoContent -- update an 'a'
1003+ :<|> DeleteNoContent -- delete an 'a'
10951004 )
10961005
10971006-- Build the appropriate 'Server'
10981007-- given the handlers of the right type.
1099−serverFor :: ExceptT ServantErr IO [a] -- handler for listing of 'a's
1100− -> (a -> ExceptT ServantErr IO ()) -- handler for adding an 'a'
1101− -> (i -> ExceptT ServantErr IO a) -- handler for viewing an 'a' given its identifier of type 'i'
1102− -> (i -> a -> ExceptT ServantErr IO ()) -- updating an 'a' with given id
1103− -> (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
11041013 -> Server (APIFor a i)
11051014serverFor = error "..."
11061015-- implementation left as an exercise. contact us on IRC
11071016-- or the mailing list if you get stuck!
11081017```
11091018
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:
1022+
1023+``` haskell
1024+type CombinedAPI2 = API :<|> "empty" :> EmptyAPI
1025+
1026+server11 :: Server CombinedAPI2
1027+server11 = server3 :<|> emptyServer
1028+```
1029+
11101030## Using another monad for your handlers
11111031
1112−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.
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.
11131034
11141035``` haskell ignore
1115−type Server api = ServerT api (ExceptT ServantErr IO)
1036+type Server api = ServerT api Handler
11161037```
11171038
1118−`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`.
11191046
1120−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?
11211050
11221051### Natural transformations
11231052
11241053If we have a function that gets us from an `m a` to an `n a`, for any `a`, what
11251054do we have?
11261055
1127−``` haskell ignore
1128−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:
11291061
1130−-- For example
1131−-- listToMaybeNat ::`[] :~> Maybe`
1132−-- listToMaybeNat = Nat listToMaybe -- from Data.Maybe
1062+``` haskell
1063+listToMaybe' :: [] ~> Maybe
1064+listToMaybe' = listToMaybe -- from Data.Maybe
11331065```
1134−(`Nat` comes from "natural transformation", in case you're wondering.)
11351066
1136−So if you want to write handlers using another monad/type than `ExceptT
1137−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
11381071prepare is a function:
11391072
11401073``` haskell ignore
1141−readerToEither :: Reader String :~> ExceptT ServantErr IO
1074+readerToHandler :: Reader String a -> Handler a
11421075```
11431076
1144−Let's start with `readerToEither'`. We obviously have to run the `Reader`
1145−computation by supplying it with a `String`, like `"hi"`. We get an `a` out
1146−from that and can then just `return` it into `ExceptT`. We can then just wrap
1147−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`.
11481080
11491081``` haskell
1150−readerToEither' :: forall a. Reader String a -> ExceptT ServantErr IO a
1151−readerToEither' r = return (runReader r "hi")
1152−
1153−readerToEither :: Reader String :~> ExceptT ServantErr IO
1154−readerToEither = Nat readerToEither'
1082+readerToHandler :: Reader String a -> Handler a
1083+readerToHandler r = return (runReader r "hi")
11551084```
11561085
11571086We can write some simple webservice with the handlers running in `Reader String`.
11581087
11591088``` haskell
11601089type ReaderAPI = "a" :> Get '[JSON] Int
1161− :<|> "b" :> Get '[JSON] String
1090+ :<|> "b" :> ReqBody '[JSON] Double :> Get '[JSON] Bool
11621091
11631092readerAPI :: Proxy ReaderAPI
11641093readerAPI = Proxy
11651094
11661095readerServerT :: ServerT ReaderAPI (Reader String)
1167−readerServerT = a :<|> b
1168−
1169− where a :: Reader String Int
1170− a = return 1797
1096+readerServerT = a :<|> b where
1097+ a :: Reader String Int
1098+ a = return 1797
11711099
1172− b :: Reader String String
1173− b = ask
1100+ b :: Double -> Reader String Bool
1101+ b _ = asks (== "hi")
11741102```
11751103
11761104We unfortunately can't use `readerServerT` as an argument of `serve`, because
1177−`serve` wants a `Server ReaderAPI`, i.e., with handlers running in `ExceptT
1178−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.
11791106
1180−### Enter `enter`
1107+### Welcome `hoistServer`
11811108
1182−That's right. We have just written `readerToEither`, which is exactly what we
1183−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
11841111right type for `serve`. Being cumbersome to do by hand, we provide a function
1185−`enter` which takes a natural transformation between two parametrized types `m`
1112+`hoistServer` which takes a natural transformation between two parameterized types `m`
11861113and `n` and a `ServerT someapi m`, and returns a `ServerT someapi n`.
11871114
1188−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.
11891117
11901118``` haskell
11911119readerServer :: Server ReaderAPI
1192−readerServer = enter readerToEither readerServerT
1120+readerServer = hoistServer readerAPI readerToHandler readerServerT
11931121
11941122app4 :: Application
1195−app4 = serve readerAPI EmptyConfig readerServer
1123+app4 = serve readerAPI readerServer
11961124```
11971125
1198−And we can indeed see this webservice in action by running `dist/build/tutorial/tutorial 7`.
1126+This is the webservice in action:
11991127
12001128``` bash
12011129$ curl http://localhost:8081/a
120211301797
1203−$ curl http://localhost:8081/b
1204−"hi"
1131+$ curl http://localhost:8081/b -X GET -d '42.0' -H 'Content-Type: application/json'
1132+true
12051133```
12061134
1207−## Conclusion
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"
12081154
1209−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*.
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)
1185+```
1186+
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.
1195+
1196+## Conclusion
12101197
1211−<div style="text-align: center;">
1212− <p><a href="/tutorial/api-type.html">Previous page: A web API as a type</a></p>
1213− <p><a href="/tutorial/client.html">Next page: Deriving Haskell functions to query an API</a></p>
1214−</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**.