@@ -5,7 +5,7 @@ type. Can we have a webservice already?
55
66## A first example
77
8−Equipped with some basic knowledge about the way we represent API, let's now
8+Equipped with some basic knowledge about the way we represent APIs, let's now
99write our first webservice.
1010
1111The source for this tutorial section is a literate haskell file, so first we
@@ -18,6 +18,7 @@ need to have some language extensions and imports:
1818{-# LANGUAGE GeneralizedNewtypeDeriving #-}
1919{-# LANGUAGE MultiParamTypeClasses #-}
2020{-# LANGUAGE OverloadedStrings #-}
21+{-# LANGUAGE RankNTypes #-}
2122{-# LANGUAGE ScopedTypeVariables #-}
2223{-# LANGUAGE TypeOperators #-}
2324
@@ -26,14 +27,14 @@ module Server where
2627import Prelude ()
2728import Prelude.Compat
2829
29−import Control.Monad.IO.Class
30+import Control.Monad.Except
3031import Control.Monad.Reader
31−import Control.Monad.Trans.Except
3232import Data.Aeson
3333import Data.Aeson.Types
3434import Data.Attoparsec.ByteString
3535import Data.ByteString (ByteString)
3636import Data.List
37+import Data.Maybe
3738import Data.String.Conversions
3839import Data.Time.Calendar
3940import GHC.Generics
@@ -45,20 +46,17 @@ import Servant
4546import System.Directory
4647import Text.Blaze
4748import Text.Blaze.Html.Renderer.Utf8
49+import Servant.Types.SourceT (source)
4850import qualified Data.Aeson.Parser
4951import qualified Text.Blaze.Html
5052```
5153
52−``` haskell ignore
53−{-# LANGUAGE TypeFamilies #-}
54−```
55−
56−**Important**: the `Servant` module comes from the *servant-server* package,
54+**Important**: the `Servant` module comes from the **servant-server** package,
5755the one that lets us run webservers that implement a particular API type. It
58−reexports all the types from the *servant* package that let you declare API
56+reexports all the types from the **servant** package that let you declare API
5957types as well as everything you need to turn your request handlers into a
6058fully-fledged webserver. This means that in your applications, you can just add
61−*servant-server* as a dependency, import `Servant` and not worry about anything
59+**servant-server** as a dependency, import `Servant` and not worry about anything
6260else.
6361
6462We will write a server that will serve the following API.
@@ -98,12 +96,6 @@ users1 =
9896 ]
9997```
10098
101−Let's also write our API type.
102−
103−``` haskell ignore
104−type UserAPI1 = "users" :> Get '[JSON] [User]
105−```
106−
10799We can now take care of writing the actual webservice that will handle requests
108100to such an API. This one will be very simple, being reduced to just a single
109101endpoint. The type of the web application is determined by the API type,
@@ -115,11 +107,11 @@ corresponding API type.
115107The first thing to know about the `Server` type family is that behind the
116108scenes it will drive the routing, letting you focus only on the business
117109logic. The second thing to know is that for each endpoint, your handlers will
118−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
119111easily, as explained near the end of this guide. Third thing, the type of the
120112value returned in that monad must be the same as the second argument of the
121113HTTP method combinator used for the corresponding endpoint. In our case, it
122−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,
123115we have a monad, let's just `return` our list:
124116
125117``` haskell
@@ -139,7 +131,7 @@ userAPI = Proxy
139131-- which you can think of as an "abstract" web application,
140132-- not yet a webserver.
141133app1 :: Application
142−app1 = serve userAPI EmptyConfig server1
134+app1 = serve userAPI server1
143135```
144136
145137The `userAPI` bit is, alas, boilerplate (we need it to guide type inference).
@@ -154,9 +146,8 @@ main = run 8081 app1
154146
155147You can put this all into a file or just grab [servant's
156148repo](http://github.com/haskell-servant/servant) and look at the
157−*servant-examples* directory. The code we have just explored is in
158−*tutorial/T1.hs*, runnable with
159−`dist/build/tutorial/tutorial 1`.
149+*doc/tutorial* directory. This code (the source of this web page) is in
150+*doc/tutorial/Server.lhs*.
160151
161152If you run it, you can go to `http://localhost:8081/users` in your browser or
162153query it with curl and you see:
@@ -192,7 +183,7 @@ users2 = [isaac, albert]
192183
193184Now, just like we separate the various endpoints in `UserAPI` with `:<|>`, we
194185are going to separate the handlers with `:<|>` too! They must be provided in
195−the same order as the one they appear in in the API type.
186+the same order as in the API type.
196187
197188``` haskell
198189server2 :: Server UserAPI2
@@ -201,15 +192,14 @@ server2 = return users2
201192 :<|> return isaac
202193```
203194
204−And that's it! You can run this example with
205−`dist/build/tutorial/tutorial 2` and check out the data available
206−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`.
207197
208198## From combinators to handler arguments
209199
210200Fine, we can write trivial webservices easily, but none of the two above use
211201any "fancy" combinator from servant. Let's address this and use `QueryParam`,
212−`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
213203combinators in an endpoint makes the corresponding handler receive an
214204argument of the appropriate type automatically. You don't have to worry about
215205manually looking up URL captures or query string parameters, or
@@ -275,15 +265,15 @@ server3 = position
275265 :<|> hello
276266 :<|> marketing
277267
278− where position :: Int -> Int -> ExceptT ServantErr IO Position
268+ where position :: Int -> Int -> Handler Position
279269 position x y = return (Position x y)
280270
281− hello :: Maybe String -> ExceptT ServantErr IO HelloMessage
271+ hello :: Maybe String -> Handler HelloMessage
282272 hello mname = return . HelloMessage $ case mname of
283273 Nothing -> "Hello, anonymous coward"
284274 Just n -> "Hello, " ++ n
285275
286− marketing :: ClientInfo -> ExceptT ServantErr IO Email
276+ marketing :: ClientInfo -> Handler Email
287277 marketing clientinfo = return (emailForClient clientinfo)
288278```
289279
@@ -298,42 +288,40 @@ parameter might not always be there);
298288
299289 - a `ReqBody contentTypeList a` becomes an argument of type `a`;
300290
301−And that's it. You can see this example in action by running
302−`dist/build/tutorial/tutorial 3`.
291+And that's it. Here's the example in action:
303292
304293``` bash
305294$ curl http://localhost:8081/position/1/2
306−{"x":1,"y":2}
295+{"xCoord":1,"yCoord":2}
307296$ curl http://localhost:8081/hello
308297{"msg":"Hello, anonymous coward"}
309298$ curl http://localhost:8081/hello?name=Alp
310299{"msg":"Hello, Alp"}
311−$ 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
312301{"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"}
313302```
314303
315−For reference, here's a list of some combinators from *servant* and for those
316−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**:
317305
318− > - `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>`.
319307 > - `Capture "something" a` becomes an argument of type `a`.
320− > - `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.
321− > - `QueryFlag "something"` and `MatrixFlag "something"` get turned into arguments of type `Bool`.
322− > - `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]`.
323311 > - `ReqBody contentTypes a` gets turned into an argument of type `a`.
324312
325313## The `FromHttpApiData`/`ToHttpApiData` classes
326314
327−Wait... How does *servant* know how to decode the `Int`s from the URL? Or how
328−to decode a `ClientInfo` value from the request body? This is what this and the
329−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.
330318
331319`Capture`s and `QueryParam`s are represented by some textual value in URLs.
332320`Header`s are similarly represented by a pair of a header name and a
333321corresponding (textual) value in the request's "metadata". How types are
334322decoded from headers, captures, and query params is expressed in a class
335323`FromHttpApiData` (from the package
336−[*http-api-data*](http://hackage.haskell.org/package/http-api-data)):
324+[**http-api-data**](http://hackage.haskell.org/package/http-api-data)):
337325
338326``` haskell ignore
339327class FromHttpApiData a where
@@ -355,15 +343,15 @@ As you can see, as long as you provide either `parseUrlPiece` (for `Capture`s)
355343or `parseQueryParam` (for `QueryParam`s), the other methods will be defined in
356344terms of this.
357345
358−*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
359347ones, and wonderful documentation.
360348
361349There's not much else to say about these classes. You will need instances for
362350them when using `Capture`, `QueryParam`, `QueryParams`, and `Header` with your
363351types. You will need `FromHttpApiData` instances for server-side request
364352handlers and `ToHttpApiData` instances only when using
365−*servant-client*, as described in the [section about deriving haskell
366−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).
367355
368356## Using content-types with your data types
369357
@@ -371,14 +359,15 @@ The same principle was operating when decoding request bodies from JSON, and
371359responses *into* JSON. (JSON is just the running example - you can do this with
372360any content-type.)
373361
374−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
375363all of this work.
376364
377365### The truth behind `JSON`
378366
379367
380−What exactly is `JSON`? Like the 3 other content types provided out of the box
381−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.
382371
383372``` haskell ignore
384373data JSON
@@ -388,14 +377,15 @@ data OctetStream
388377```
389378
390379Obviously, this is not all there is to `JSON`, otherwise it would be quite
391−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
392381a special *symbol* that's associated with encoding (resp. decoding) to (resp.
393382from) the *JSON* format. The way this association is performed can be
394383decomposed into two steps.
395384
396385The first step is to provide a proper
397−[`MediaType`](https://hackage.haskell.org/package/http-media-0.6.2/docs/Network-HTTP-Media.html)
398−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
399389haddocks from this link, you can see that we just have to specify
400390`application/json` using the appropriate functions. In our case, we can just
401391use `(//) :: ByteString -> ByteString -> MediaType`. The precise way to specify
@@ -411,14 +401,14 @@ instance Accept JSON where
411401```
412402
413403The second step is centered around the `MimeRender` and `MimeUnrender` classes.
414−These classes just let you specify a way to respectively encode and decode
415−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.
416406
417407``` haskell ignore
418408class Accept ctype => MimeRender ctype a where
419− mimeRender :: Proxy ctype -> a -> ByteString
409+ mimeRender :: Proxy ctype -> a -> ByteString
420410 -- alternatively readable as:
421− mimeRender :: Proxy ctype -> (a -> ByteString)
411+ mimeRender :: Proxy ctype -> (a -> ByteString)
422412```
423413
424414Given a content-type and some user type, `MimeRender` provides a function that
@@ -444,7 +434,7 @@ class Accept ctype => MimeUnrender ctype a where
444434We don't have much work to do there either, `Data.Aeson.eitherDecode` is
445435precisely what we need. However, it only allows arrays and objects as toplevel
446436JSON values and this has proven to get in our way more than help us so we wrote
447−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
448438JSON value at the toplevel of a "JSON document". Here's the definition in case
449439you are curious.
450440
@@ -462,20 +452,20 @@ instance FromJSON a => MimeUnrender JSON a where
462452 mimeUnrender _ = eitherDecodeLenient
463453```
464454
465−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`,
466456`Post` and friends. We can check our understanding by implementing support
467−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
468458HTML representation of the data they want, ready to be included in any HTML
469459document, e.g. using [jQuery's `load` function](https://api.jquery.com/load/),
470460simply by adding `Accept: text/html` to their request headers.
471461
472−### Case-studies: *servant-blaze* and *servant-lucid*
462+### Case-studies: **servant-blaze** and **servant-lucid**
473463
474464These days, most of the haskellers who write their HTML UIs directly from
475−Haskell use either [blaze-html](http://hackage.haskell.org/package/blaze-html)
476−or [lucid](http://hackage.haskell.org/package/lucid). The best option for
477−*servant* is obviously to support both (and hopefully other templating
478−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**:
479469
480470``` haskell
481471data HTMLLucid
@@ -483,24 +473,20 @@ data HTMLLucid
483473
484474Once again, the data type is just there as a symbol for the encoding/decoding
485475functions, except that this time we will only worry about encoding since
486−*blaze-html* and *lucid* don't provide a way to extract data from HTML.
487−
488−Both packages also have the same `Accept` instance for their `HTMLLucid` type.
476+**lucid** doesn't provide a way to extract data from HTML.
489477
490478``` haskell
491479instance Accept HTMLLucid where
492480 contentType _ = "text" // "html" /: ("charset", "utf-8")
493481```
494482
495−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
496484us specify additional information about a content-type, like the charset here.
497485
498−The rendering instances for both packages both call similar functions that take
486+The rendering instances call similar functions that take
499487types with an appropriate instance to an "abstract" HTML representation and
500488then write that to a `ByteString`.
501489
502−For *lucid*:
503−
504490``` haskell
505491instance ToHtml a => MimeRender HTMLLucid a where
506492 mimeRender _ = renderBS . toHtml
@@ -511,7 +497,7 @@ instance MimeRender HTMLLucid (Html a) where
511497 mimeRender _ = renderBS
512498```
513499
514−For *blaze-html*:
500+For **blaze-html** everything works very similarly:
515501
516502``` haskell
517503-- For this tutorial to compile 'HTMLLucid' and 'HTMLBlaze' have to be
@@ -531,15 +517,13 @@ instance MimeRender HTMLBlaze Text.Blaze.Html.Html where
531517 mimeRender _ = renderHtml
532518```
533519
534−Both [servant-blaze](http://hackage.haskell.org/package/servant-blaze) and
535−[servant-lucid](http://hackage.haskell.org/package/servant-lucid) let you use
536−`HTMLLucid` in any content type list as long as you provide an instance of the
537−appropriate class (`ToMarkup` for *blaze-html*, `ToHtml` for *lucid*).
538−
539−We can now write webservice that uses *servant-lucid* to show the `HTMLLucid`
540−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**).
541524
542−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:
543527
544528``` haskell
545529type PersonAPI = "persons" :> Get '[JSON, HTMLLucid] [Person]
@@ -556,7 +540,7 @@ data Person = Person
556540instance ToJSON Person
557541```
558542
559−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
560544a list of `Person`s as a table with a row per person.
561545
562546``` haskell
@@ -600,48 +584,45 @@ server4 :: Server PersonAPI
600584server4 = return people
601585
602586app2 :: Application
603−app2 = serve personAPI EmptyConfig server4
587+app2 = serve personAPI server4
604588```
605589
606−And we're good to go. You can run this example with `dist/build/tutorial/tutorial 4`.
590+And we're good to go:
607591
608592``` bash
609− $ curl http://localhost:8081/persons
610− [{"lastName":"Newton","firstName":"Isaac"},{"lastName":"Einstein","firstName":"Albert"}]
611− $ curl -H 'Accept: text/html' http://localhost:8081/persons
612− <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>
613− # 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
614598```
615599
616−## The `ExceptT ServantErr IO` monad
600+## The `Handler` monad
617601
618−At the heart of the handlers is the monad they run in, namely `ExceptT
619−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
620605simplest monad with the following properties:
621606
622−- it lets us both return a successful result (with the `Right` branch of
623−`Either`) or "fail" with a descriptive error (with the `Left` branch of
624−`Either`);
607+- it lets us both return a successful result (using `return`)
608+or "fail" with a descriptive error (using `throwError`);
625609- it lets us perform IO, which is absolutely vital since most webservices exist
626−as interfaces to databases that we interact with in `IO`;
610+as interfaces to databases that we interact with in `IO`.
627611
628612Let's recall some definitions.
629613
630614``` haskell ignore
631−-- from the Prelude
632−data Either e a = Left e | Right a
633−
634615-- from the 'mtl' package at
635−newtype ExceptT e m a = ExceptT ( m (Either e a) )
616+newtype ExceptT e m a = ExceptT (m (Either e a))
636617```
637618
638−In short, this means that a handler of type `ExceptT ServantErr IO a` is simply
639−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
640621action that either returns an error or a result.
641622
642−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)
643624from which `ExceptT` comes is worth looking at.
644−Perhaps most importantly, `ExceptT` is an instance of `MonadError`, so
625+Perhaps most importantly, `ExceptT` and `Handler` are instances of `MonadError`, so
645626`throwError` can be used to return an error from your handler (whereas `return`
646627 is enough to return a success).
647628
@@ -651,18 +632,17 @@ kind and abort early. The next two sections cover how to do just that.
651632
652633### Performing IO
653634
654−Another important instance from the list above is `MonadIO m => MonadIO
655−(ExceptT e m)`.
656−[`MonadIO`](http://hackage.haskell.org/package/transformers-0.4.3.0/docs/Control-Monad-IO-Class.html)
657−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:
658639
659640``` haskell ignore
660641class Monad m => MonadIO m where
661642 liftIO :: IO a -> m a
662643```
663644
664−Obviously, the `IO` monad provides a `MonadIO` instance. Hence for any type
665−`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
666646IO computation in your handlers, just use `liftIO`:
667647
668648``` haskell
@@ -680,16 +660,16 @@ server5 = do
680660 return (FileContent filecontent)
681661```
682662
683−### Failing, through `ServantErr`
663+### Failing, through `ServerError`
684664
685665If you want to explicitly fail at providing the result promised by an endpoint
686666using the appropriate HTTP status code (not found, unauthorized, etc) and some
687−error message, all you have to do is use the `left` function mentioned above
688−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
689669defined as:
690670
691671``` haskell ignore
692−data ServantErr = ServantErr
672+data ServerError = ServerError
693673 { errHTTPCode :: Int
694674 , errReasonPhrase :: String
695675 , errBody :: ByteString -- lazy bytestring
@@ -702,10 +682,10 @@ module. If you want to use these values but add a body or some headers, just
702682use record update syntax:
703683
704684``` haskell
705−failingHandler :: ExceptT ServantErr IO ()
706−failingHandler = throwE myerr
685+failingHandler :: Handler ()
686+failingHandler = throwError myerr
707687
708− where myerr :: ServantErr
688+ where myerr :: ServerError
709689 myerr = err503 { errBody = "Sorry dear user." }
710690```
711691
@@ -718,42 +698,41 @@ server6 = do
718698 exists <- liftIO (doesFileExist "myfile.txt")
719699 if exists
720700 then liftIO (readFile "myfile.txt") >>= return . FileContent
721− else throwE custom404Err
701+ else throwError custom404Err
722702
723703 where custom404Err = err404 { errBody = "myfile.txt just isn't there, please leave this server alone." }
724704```
725705
726−Let's run this server (`dist/build/tutorial/tutorial 5`) and
727−query it, first without the file and then with the file.
706+Here's how that server looks in action:
728707
729708``` bash
730− $ curl --verbose http://localhost:8081/myfile.txt
731− [snip]
732− * Connected to localhost (127.0.0.1) port 8081 (#0)
733− > GET /myfile.txt HTTP/1.1
734− > User-Agent: curl/7.30.0
735− > Host: localhost:8081
736− > Accept: */*
737− >
738− < HTTP/1.1 404 Not Found
739− [snip]
740− myfile.txt just isnt there, please leave this server alone.
741−
742− $ echo Hello > myfile.txt
743−
744− $ curl --verbose http://localhost:8081/myfile.txt
745− [snip]
746− * Connected to localhost (127.0.0.1) port 8081 (#0)
747− > GET /myfile.txt HTTP/1.1
748− > User-Agent: curl/7.30.0
749− > Host: localhost:8081
750− > Accept: */*
751− >
752− < HTTP/1.1 200 OK
753− [snip]
754− < Content-Type: application/json
755− [snip]
756− {"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"}
757736```
758737
759738## Response headers
@@ -769,151 +748,77 @@ myHandler :: Server MyHandler
769748myHandler = return $ addHeader 1797 albert
770749```
771750
772−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+```
773774
774775## Serving static files
775776
776−*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
777778under some path in your web API. As mentioned earlier in this document, the
778779`Raw` combinator can be used in your APIs to mean "plug here any WAI
779−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
780781directory serving WAI application, namely:
781782
782783``` haskell ignore
783784-- exported by Servant and Servant.Server
784−serveDirectory :: FilePath -> Server Raw
785+serveDirectoryWebApp :: FilePath -> Server Raw
785786```
786787
787−`serveDirectory`'s argument must be a path to a valid directory. You can see an
788−example below, runnable with `dist/build/tutorial/tutorial 6`
789−(you **must** run it from within the *servant-examples/* directory!), which is
790−a webserver that serves the various bits of code covered in this
791−getting-started.
788+`serveDirectoryWebApp`'s argument must be a path to a valid directory.
792789
793−The API type will be the following.
790+Here's an example API that will serve some static files:
794791
795792``` haskell
796−type CodeAPI = "code" :> Raw
793+type StaticAPI = "static" :> Raw
797794```
798795
799796And the server:
800797
801798``` haskell
802−codeAPI :: Proxy CodeAPI
803−codeAPI = Proxy
799+staticAPI :: Proxy StaticAPI
800+staticAPI = Proxy
804801```
805802
806803``` haskell
807−server7 :: Server CodeAPI
808−server7 = serveDirectory "tutorial"
804+server7 :: Server StaticAPI
805+server7 = serveDirectoryWebApp "static-files"
809806
810807app3 :: Application
811−app3 = serve codeAPI EmptyConfig server7
808+app3 = serve staticAPI server7
812809```
813810
814−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
815812for a file at the path described by the rest of the request path, inside the
816− *tutorial/* directory of the path you run the program from.
813+ *static-files/* directory of the path you run the program from.
817814
818−In other words:
815+In other words: If a client requests `/static/foo.txt`, the server will look for a file at
816+`./static-files/foo.txt`. If that file exists it'll succeed and serve the file.
817+If it doesn't exist, the handler will fail with a `404` status code.
819818
820−- If a client requests `/code/foo.txt`, the server will look for a file at
821− `./tutorial/foo.txt` (and fail)
822−- If a client requests `/code/T1.hs`, the server will look for a file at
823− `./tutorial/T1.hs` (and succeed)
824−- If a client requests `/code/foo/bar/baz/movie.mp4`, the server will look for
825− a file at `./tutorial/foo/bar/baz/movie.mp4` (and fail)
826−
827−Here is our little server in action.
828−
829−``` haskell ignore
830−$ curl http://localhost:8081/code/T1.hs
831−{-# LANGUAGE DataKinds #-}
832−{-# LANGUAGE TypeFamilies #-}
833−{-# LANGUAGE DeriveGeneric #-}
834−{-# LANGUAGE TypeOperators #-}
835−module T1 where
836−
837−import Data.Aeson
838−import Data.Time.Calendar
839−import GHC.Generics
840−import Network.Wai
841−import Servant
842−
843−data User = User
844− { name :: String
845− , age :: Int
846− , email :: String
847− , registration_date :: Day
848− } deriving (Eq, Show, Generic)
849−
850−-- orphan ToJSON instance for Day. necessary to derive one for User
851−instance ToJSON Day where
852− -- display a day in YYYY-mm-dd format
853− toJSON d = toJSON (showGregorian d)
854−
855−instance ToJSON User
856−
857−type UserAPI = "users" :> Get '[JSON] [User]
858−
859−users :: [User]
860−users =
861− [ User "Isaac Newton" 372 "isaac@newton.co.uk" (fromGregorian 1683 3 1)
862− , User "Albert Einstein" 136 "ae@mc2.org" (fromGregorian 1905 12 1)
863− ]
864−
865−userAPI :: Proxy UserAPI
866−userAPI = Proxy
867−
868−server :: Server UserAPI
869−server = return users
870−
871−app :: Application
872−app = serve userAPI server
873−$ curl http://localhost:8081/code/tutorial.hs
874−import Network.Wai
875−import Network.Wai.Handler.Warp
876−import System.Environment
877−
878−import qualified T1
879−import qualified T2
880−import qualified T3
881−import qualified T4
882−import qualified T5
883−import qualified T6
884−import qualified T7
885−import qualified T9
886−import qualified T10
887−
888−app :: String -> (Application -> IO ()) -> IO ()
889−app n f = case n of
890− "1" -> f T1.app
891− "2" -> f T2.app
892− "3" -> f T3.app
893− "4" -> f T4.app
894− "5" -> f T5.app
895− "6" -> f T6.app
896− "7" -> f T7.app
897− "8" -> f T3.app
898− "9" -> T9.writeJSFiles >> f T9.app
899− "10" -> f T10.app
900− _ -> usage
901−
902−main :: IO ()
903−main = do
904− args <- getArgs
905− case args of
906− [n] -> app n (run 8081)
907− _ -> usage
908−
909−usage :: IO ()
910−usage = do
911− putStrLn "Usage:\t tutorial N"
912− putStrLn "\t\twhere N is the number of the example you want to run."
913−
914−$ curl http://localhost:8081/foo
915−not found
916−```
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.
917822
918823## Nested APIs
919824
@@ -925,7 +830,7 @@ type UserAPI3 = -- view the user with given userid, in JSON
925830 Capture "userid" Int :> Get '[JSON] User
926831
927832 :<|> -- delete the user with given userid. empty response
928− Capture "userid" Int :> Delete '[] ()
833+ Capture "userid" Int :> DeleteNoContent
929834```
930835
931836We can instead factor out the `userid`:
@@ -933,7 +838,7 @@ We can instead factor out the `userid`:
933838``` haskell
934839type UserAPI4 = Capture "userid" Int :>
935840 ( Get '[JSON] User
936− :<|> Delete '[] ()
841+ :<|> DeleteNoContent
937842 )
938843```
939844
@@ -941,26 +846,26 @@ However, you have to be aware that this has an effect on the type of the
941846corresponding `Server`:
942847
943848``` haskell ignore
944−Server UserAPI3 = (Int -> ExceptT ServantErr IO User)
945− :<|> (Int -> ExceptT ServantErr IO ())
849+Server UserAPI3 = (Int -> Handler User)
850+ :<|> (Int -> Handler NoContent)
946851
947−Server UserAPI4 = Int -> ( ExceptT ServantErr IO User
948− :<|> ExceptT ServantErr IO ()
852+Server UserAPI4 = Int -> ( Handler User
853+ :<|> Handler NoContent
949854 )
950855```
951856
952857In the first case, each handler receives the *userid* argument. In the latter,
953858the whole `Server` takes the *userid* and has handlers that are just
954−computations in `ExceptT`, with no arguments. In other words:
859+computations in `Handler`, with no arguments. In other words:
955860
956861``` haskell
957862server8 :: Server UserAPI3
958863server8 = getUser :<|> deleteUser
959864
960− where getUser :: Int -> ExceptT ServantErr IO User
865+ where getUser :: Int -> Handler User
961866 getUser _userid = error "..."
962867
963− deleteUser :: Int -> ExceptT ServantErr IO ()
868+ deleteUser :: Int -> Handler NoContent
964869 deleteUser _userid = error "..."
965870
966871-- notice how getUser and deleteUser
@@ -969,10 +874,10 @@ server8 = getUser :<|> deleteUser
969874server9 :: Server UserAPI4
970875server9 userid = getUser userid :<|> deleteUser userid
971876
972− where getUser :: Int -> ExceptT ServantErr IO User
877+ where getUser :: Int -> Handler User
973878 getUser = error "..."
974879
975− deleteUser :: Int -> ExceptT ServantErr IO ()
880+ deleteUser :: Int -> Handler NoContent
976881 deleteUser = error "..."
977882```
978883
@@ -991,13 +896,13 @@ type API1 = "users" :>
991896-- we factor out the Request Body
992897type API2 = ReqBody '[JSON] User :>
993898 ( Get '[JSON] User -- just display the same user back, don't register it
994− :<|> Post '[JSON] () -- register the user. empty response
899+ :<|> PostNoContent -- register the user. empty response
995900 )
996901
997902-- we factor out a Header
998903type API3 = Header "Authorization" Token :>
999904 ( Get '[JSON] SecretData -- get some secret data, if authorized
1000− :<|> ReqBody '[JSON] SecretData :> Post '[] () -- add some secret data, if authorized
905+ :<|> ReqBody '[JSON] SecretData :> PostNoContent -- add some secret data, if authorized
1001906 )
1002907
1003908newtype Token = Token ByteString
@@ -1010,44 +915,44 @@ API type only at the end.
1010915``` haskell
1011916type UsersAPI =
1012917 Get '[JSON] [User] -- list users
1013− :<|> ReqBody '[JSON] User :> Post '[] () -- add a user
918+ :<|> ReqBody '[JSON] User :> PostNoContent -- add a user
1014919 :<|> Capture "userid" Int :>
1015920 ( Get '[JSON] User -- view a user
1016− :<|> ReqBody '[JSON] User :> Put '[] () -- update a user
1017− :<|> Delete '[] () -- delete a user
921+ :<|> ReqBody '[JSON] User :> PutNoContent -- update a user
922+ :<|> DeleteNoContent -- delete a user
1018923 )
1019924
1020925usersServer :: Server UsersAPI
1021926usersServer = getUsers :<|> newUser :<|> userOperations
1022927
1023− where getUsers :: ExceptT ServantErr IO [User]
928+ where getUsers :: Handler [User]
1024929 getUsers = error "..."
1025930
1026− newUser :: User -> ExceptT ServantErr IO ()
931+ newUser :: User -> Handler NoContent
1027932 newUser = error "..."
1028933
1029934 userOperations userid =
1030935 viewUser userid :<|> updateUser userid :<|> deleteUser userid
1031936
1032937 where
1033− viewUser :: Int -> ExceptT ServantErr IO User
938+ viewUser :: Int -> Handler User
1034939 viewUser = error "..."
1035940
1036− updateUser :: Int -> User -> ExceptT ServantErr IO ()
941+ updateUser :: Int -> User -> Handler NoContent
1037942 updateUser = error "..."
1038943
1039− deleteUser :: Int -> ExceptT ServantErr IO ()
944+ deleteUser :: Int -> Handler NoContent
1040945 deleteUser = error "..."
1041946```
1042947
1043948``` haskell
1044949type ProductsAPI =
1045950 Get '[JSON] [Product] -- list products
1046− :<|> ReqBody '[JSON] Product :> Post '[] () -- add a product
951+ :<|> ReqBody '[JSON] Product :> PostNoContent -- add a product
1047952 :<|> Capture "productid" Int :>
1048953 ( Get '[JSON] Product -- view a product
1049− :<|> ReqBody '[JSON] Product :> Put '[] () -- update a product
1050− :<|> Delete '[] () -- delete a product
954+ :<|> ReqBody '[JSON] Product :> PutNoContent -- update a product
955+ :<|> DeleteNoContent -- delete a product
1051956 )
1052957
1053958data Product = Product { productId :: Int }
@@ -1055,23 +960,23 @@ data Product = Product { productId :: Int }
1055960productsServer :: Server ProductsAPI
1056961productsServer = getProducts :<|> newProduct :<|> productOperations
1057962
1058− where getProducts :: ExceptT ServantErr IO [Product]
963+ where getProducts :: Handler [Product]
1059964 getProducts = error "..."
1060965
1061− newProduct :: Product -> ExceptT ServantErr IO ()
966+ newProduct :: Product -> Handler NoContent
1062967 newProduct = error "..."
1063968
1064969 productOperations productid =
1065970 viewProduct productid :<|> updateProduct productid :<|> deleteProduct productid
1066971
1067972 where
1068− viewProduct :: Int -> ExceptT ServantErr IO Product
973+ viewProduct :: Int -> Handler Product
1069974 viewProduct = error "..."
1070975
1071− updateProduct :: Int -> Product -> ExceptT ServantErr IO ()
976+ updateProduct :: Int -> Product -> Handler NoContent
1072977 updateProduct = error "..."
1073978
1074− deleteProduct :: Int -> ExceptT ServantErr IO ()
979+ deleteProduct :: Int -> Handler NoContent
1075980 deleteProduct = error "..."
1076981```
1077982
@@ -1091,39 +996,49 @@ abstract that away:
1091996-- indexed by values of type 'i'
1092997type APIFor a i =
1093998 Get '[JSON] [a] -- list 'a's
1094− :<|> ReqBody '[JSON] a :> Post '[] () -- add an 'a'
999+ :<|> ReqBody '[JSON] a :> PostNoContent -- add an 'a'
10951000 :<|> Capture "id" i :>
10961001 ( Get '[JSON] a -- view an 'a' given its "identifier" of type 'i'
1097− :<|> ReqBody '[JSON] a :> Put '[] () -- update an 'a'
1098− :<|> Delete '[] () -- delete an 'a'
1002+ :<|> ReqBody '[JSON] a :> PutNoContent -- update an 'a'
1003+ :<|> DeleteNoContent -- delete an 'a'
10991004 )
11001005
11011006-- Build the appropriate 'Server'
11021007-- given the handlers of the right type.
1103−serverFor :: ExceptT ServantErr IO [a] -- handler for listing of 'a's
1104− -> (a -> ExceptT ServantErr IO ()) -- handler for adding an 'a'
1105− -> (i -> ExceptT ServantErr IO a) -- handler for viewing an 'a' given its identifier of type 'i'
1106− -> (i -> a -> ExceptT ServantErr IO ()) -- updating an 'a' with given id
1107− -> (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
11081013 -> Server (APIFor a i)
11091014serverFor = error "..."
11101015-- implementation left as an exercise. contact us on IRC
11111016-- or the mailing list if you get stuck!
11121017```
11131018
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+
11141030## Using another monad for your handlers
11151031
1116−Remember how `Server` turns combinators for HTTP methods into `ExceptT
1117−ServantErr IO`? Well, actually, there's more to that. `Server` is actually a
1032+Remember how `Server` turns combinators for HTTP methods into `Handler`? Well, actually, there's more to that. `Server` is actually a
11181033simple type synonym.
11191034
11201035``` haskell ignore
1121−type Server api = ServerT api (ExceptT ServantErr IO)
1036+type Server api = ServerT api Handler
11221037```
11231038
11241039`ServerT` is the actual type family that computes the required types for the
11251040handlers that's part of the `HasServer` class. It's like `Server` except that
1126−it takes a third parameter which is the monad you want your handlers to run in,
1041+it takes another parameter which is the monad you want your handlers to run in,
11271042or more generally the return types of your handlers. This third parameter is
11281043used for specifying the return type of the handler for an endpoint, e.g when
11291044computing `ServerT (Get '[JSON] Person) SomeMonad`. The result would be
@@ -1131,98 +1046,155 @@ computing `ServerT (Get '[JSON] Person) SomeMonad`. The result would be
11311046
11321047The first and main question one might have then is: how do we write handlers
11331048that run in another monad? How can we "bring back" the value from a given monad
1134−into something *servant* can understand?
1049+into something **servant** can understand?
11351050
11361051### Natural transformations
11371052
11381053If we have a function that gets us from an `m a` to an `n a`, for any `a`, what
11391054do we have?
11401055
1141−``` haskell ignore
1142−newtype m :~> n = Nat { unNat :: forall a. m a -> n a}
1056+``` haskell
1057+type (~>) m n = forall a. m a -> n a
1058+```
11431059
1144−-- For example
1145−-- listToMaybeNat ::`[] :~> Maybe`
1146−-- listToMaybeNat = Nat listToMaybe -- from Data.Maybe
1060+For example:
1061+
1062+``` haskell
1063+listToMaybe' :: [] ~> Maybe
1064+listToMaybe' = listToMaybe -- from Data.Maybe
11471065```
1148−(`Nat` comes from "natural transformation", in case you're wondering.)
11491066
1150−So if you want to write handlers using another monad/type than `ExceptT
1151−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
11521071prepare is a function:
11531072
11541073``` haskell ignore
1155−readerToEither :: Reader String :~> ExceptT ServantErr IO
1074+readerToHandler :: Reader String a -> Handler a
11561075```
11571076
1158−Let's start with `readerToEither'`. We obviously have to run the `Reader`
1159−computation by supplying it with a `String`, like `"hi"`. We get an `a` out
1160−from that and can then just `return` it into `ExceptT`. We can then just wrap
1161−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`.
11621080
11631081``` haskell
1164−readerToEither' :: forall a. Reader String a -> ExceptT ServantErr IO a
1165−readerToEither' r = return (runReader r "hi")
1166−
1167−readerToEither :: Reader String :~> ExceptT ServantErr IO
1168−readerToEither = Nat readerToEither'
1082+readerToHandler :: Reader String a -> Handler a
1083+readerToHandler r = return (runReader r "hi")
11691084```
11701085
11711086We can write some simple webservice with the handlers running in `Reader String`.
11721087
11731088``` haskell
11741089type ReaderAPI = "a" :> Get '[JSON] Int
1175− :<|> "b" :> Get '[JSON] String
1090+ :<|> "b" :> ReqBody '[JSON] Double :> Get '[JSON] Bool
11761091
11771092readerAPI :: Proxy ReaderAPI
11781093readerAPI = Proxy
11791094
11801095readerServerT :: ServerT ReaderAPI (Reader String)
1181−readerServerT = a :<|> b
1182−
1183− where a :: Reader String Int
1184− a = return 1797
1096+readerServerT = a :<|> b where
1097+ a :: Reader String Int
1098+ a = return 1797
11851099
1186− b :: Reader String String
1187− b = ask
1100+ b :: Double -> Reader String Bool
1101+ b _ = asks (== "hi")
11881102```
11891103
11901104We unfortunately can't use `readerServerT` as an argument of `serve`, because
1191−`serve` wants a `Server ReaderAPI`, i.e., with handlers running in `ExceptT
1192−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.
11931106
1194−### Enter `enter`
1107+### Welcome `hoistServer`
11951108
1196−That's right. We have just written `readerToEither`, which is exactly what we
1197−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
11981111right type for `serve`. Being cumbersome to do by hand, we provide a function
1199−`enter` which takes a natural transformation between two parametrized types `m`
1112+`hoistServer` which takes a natural transformation between two parameterized types `m`
12001113and `n` and a `ServerT someapi m`, and returns a `ServerT someapi n`.
12011114
1202−In our case, we can wrap up our little webservice by using `enter
1203−readerToEither` on our handlers.
1115+In our case, we can wrap up our little webservice by using
1116+`hoistServer readerAPI readerToHandler` on our handlers.
12041117
12051118``` haskell
12061119readerServer :: Server ReaderAPI
1207−readerServer = enter readerToEither readerServerT
1120+readerServer = hoistServer readerAPI readerToHandler readerServerT
12081121
12091122app4 :: Application
1210−app4 = serve readerAPI EmptyConfig readerServer
1123+app4 = serve readerAPI readerServer
12111124```
12121125
1213−And we can indeed see this webservice in action by running
1214−`dist/build/tutorial/tutorial 7`.
1126+This is the webservice in action:
12151127
12161128``` bash
12171129$ curl http://localhost:8081/a
121811301797
1219−$ curl http://localhost:8081/b
1220−"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)
12211160```
12221161
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+
12231196## Conclusion
12241197
1225−You're now equipped to write any kind of webservice/web-application using
1226−*servant*. One thing not covered here is how to incorporate your own
1227−combinators and will be the topic of a page on the website. The rest of this
1228−document focuses on *servant-client*, *servant-jquery* and *servant-docs*.
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**.