@@ -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 APIs, let's now
8+Equipped with some basic knowledge about the way we represent API, let's now
99write our first webservice.
1010
1111The source for this tutorial section is a literate haskell file, so first we
@@ -18,7 +18,6 @@ need to have some language extensions and imports:
1818{-# LANGUAGE GeneralizedNewtypeDeriving #-}
1919{-# LANGUAGE MultiParamTypeClasses #-}
2020{-# LANGUAGE OverloadedStrings #-}
21−{-# LANGUAGE RankNTypes #-}
2221{-# LANGUAGE ScopedTypeVariables #-}
2322{-# LANGUAGE TypeOperators #-}
2423
@@ -27,14 +26,14 @@ module Server where
2726import Prelude ()
2827import Prelude.Compat
2928
30−import Control.Monad.Except
29+import Control.Monad.IO.Class
3130import Control.Monad.Reader
32−import Data.Aeson
31+import Control.Monad.Trans.Except
32+import Data.Aeson.Compat
3333import Data.Aeson.Types
3434import Data.Attoparsec.ByteString
3535import Data.ByteString (ByteString)
3636import Data.List
37−import Data.Maybe
3837import Data.String.Conversions
3938import Data.Time.Calendar
4039import GHC.Generics
@@ -46,17 +45,20 @@ import Servant
4645import System.Directory
4746import Text.Blaze
4847import Text.Blaze.Html.Renderer.Utf8
49−import Servant.Types.SourceT (source)
5048import qualified Data.Aeson.Parser
5149import qualified Text.Blaze.Html
5250```
5351
54−**Important**: the `Servant` module comes from the **servant-server** package,
52+``` haskell ignore
53+{-# LANGUAGE TypeFamilies #-}
54+```
55+
56+**Important**: the `Servant` module comes from the *servant-server* package,
5557the 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
58+reexports all the types from the *servant* package that let you declare API
5759types as well as everything you need to turn your request handlers into a
5860fully-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
61+*servant-server* as a dependency, import `Servant` and not worry about anything
6062else.
6163
6264We will write a server that will serve the following API.
@@ -96,6 +98,12 @@ users1 =
9698 ]
9799```
98100
101+Let's also write our API type.
102+
103+``` haskell ignore
104+type UserAPI1 = "users" :> Get '[JSON] [User]
105+```
106+
99107We can now take care of writing the actual webservice that will handle requests
100108to such an API. This one will be very simple, being reduced to just a single
101109endpoint. The type of the web application is determined by the API type,
@@ -107,11 +115,11 @@ corresponding API type.
107115The first thing to know about the `Server` type family is that behind the
108116scenes it will drive the routing, letting you focus only on the business
109117logic. The second thing to know is that for each endpoint, your handlers will
110−by default run in the `Handler` monad. This is overridable very
118+by default run in the `ExceptT ServantErr IO` monad. This is overridable very
111119easily, as explained near the end of this guide. Third thing, the type of the
112120value returned in that monad must be the same as the second argument of the
113121HTTP method combinator used for the corresponding endpoint. In our case, it
114−means we must provide a handler of type `Handler [User]`. Well,
122+means we must provide a handler of type `ExceptT ServantErr IO [User]`. Well,
115123we have a monad, let's just `return` our list:
116124
117125``` haskell
@@ -146,8 +154,9 @@ main = run 8081 app1
146154
147155You can put this all into a file or just grab [servant's
148156repo](http://github.com/haskell-servant/servant) and look at the
149−*doc/tutorial* directory. This code (the source of this web page) is in
150−*doc/tutorial/Server.lhs*.
157+*servant-examples* directory. The code we have just explored is in
158+*tutorial/T1.hs*, runnable with
159+`dist/build/tutorial/tutorial 1`.
151160
152161If you run it, you can go to `http://localhost:8081/users` in your browser or
153162query it with curl and you see:
@@ -183,7 +192,7 @@ users2 = [isaac, albert]
183192
184193Now, just like we separate the various endpoints in `UserAPI` with `:<|>`, we
185194are going to separate the handlers with `:<|>` too! They must be provided in
186−the same order as in the API type.
195+the same order as the one they appear in in the API type.
187196
188197``` haskell
189198server2 :: Server UserAPI2
@@ -192,14 +201,15 @@ server2 = return users2
192201 :<|> return isaac
193202```
194203
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`.
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`.
197207
198208## From combinators to handler arguments
199209
200210Fine, we can write trivial webservices easily, but none of the two above use
201211any "fancy" combinator from servant. Let's address this and use `QueryParam`,
202−`Capture` and `ReqBody` right away. You'll see how each occurrence of these
212+`Capture` and `ReqBody` right away. You'll see how each occurence of these
203213combinators in an endpoint makes the corresponding handler receive an
204214argument of the appropriate type automatically. You don't have to worry about
205215manually looking up URL captures or query string parameters, or
@@ -265,15 +275,15 @@ server3 = position
265275 :<|> hello
266276 :<|> marketing
267277
268− where position :: Int -> Int -> Handler Position
278+ where position :: Int -> Int -> ExceptT ServantErr IO Position
269279 position x y = return (Position x y)
270280
271− hello :: Maybe String -> Handler HelloMessage
281+ hello :: Maybe String -> ExceptT ServantErr IO HelloMessage
272282 hello mname = return . HelloMessage $ case mname of
273283 Nothing -> "Hello, anonymous coward"
274284 Just n -> "Hello, " ++ n
275285
276− marketing :: ClientInfo -> Handler Email
286+ marketing :: ClientInfo -> ExceptT ServantErr IO Email
277287 marketing clientinfo = return (emailForClient clientinfo)
278288```
279289
@@ -288,40 +298,42 @@ parameter might not always be there);
288298
289299 - a `ReqBody contentTypeList a` becomes an argument of type `a`;
290300
291−And that's it. Here's the example in action:
301+And that's it. You can see this example in action by running
302+`dist/build/tutorial/tutorial 3`.
292303
293304``` bash
294305$ curl http://localhost:8081/position/1/2
295−{"xCoord":1,"yCoord":2}
306+{"x":1,"y":2}
296307$ curl http://localhost:8081/hello
297308{"msg":"Hello, anonymous coward"}
298309$ curl http://localhost:8081/hello?name=Alp
299310{"msg":"Hello, Alp"}
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
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
301312{"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"}
302313```
303314
304−For reference, here's a list of some combinators from **servant**:
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.
305317
306− > - `Delete`, `Get`, `Patch`, `Post`, `Put`: these do not become arguments. They provide the return type of handlers, which usually is `Handler <something>`.
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>`.
307319 > - `Capture "something" a` becomes an argument 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]`.
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]`.
311323 > - `ReqBody contentTypes a` gets turned into an argument of type `a`.
312324
313325## The `FromHttpApiData`/`ToHttpApiData` classes
314326
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.
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.
318330
319331`Capture`s and `QueryParam`s are represented by some textual value in URLs.
320332`Header`s are similarly represented by a pair of a header name and a
321333corresponding (textual) value in the request's "metadata". How types are
322334decoded from headers, captures, and query params is expressed in a class
323335`FromHttpApiData` (from the package
324−[**http-api-data**](http://hackage.haskell.org/package/http-api-data)):
336+[*http-api-data*](http://hackage.haskell.org/package/http-api-data)):
325337
326338``` haskell ignore
327339class FromHttpApiData a where
@@ -343,15 +355,15 @@ As you can see, as long as you provide either `parseUrlPiece` (for `Capture`s)
343355or `parseQueryParam` (for `QueryParam`s), the other methods will be defined in
344356terms of this.
345357
346−**http-api-data** provides a decent number of instances, helpers for defining new
358+*http-api-data* provides a decent number of instances, helpers for defining new
347359ones, and wonderful documentation.
348360
349361There's not much else to say about these classes. You will need instances for
350362them when using `Capture`, `QueryParam`, `QueryParams`, and `Header` with your
351363types. You will need `FromHttpApiData` instances for server-side request
352364handlers and `ToHttpApiData` instances only when using
353−**servant-client**, as described in the [section about deriving haskell
354−functions to query an API](Client.html).
365+*servant-client*, as described in the [section about deriving haskell
366+functions to query an API](/tutorial/client.html).
355367
356368## Using content-types with your data types
357369
@@ -359,15 +371,14 @@ The same principle was operating when decoding request bodies from JSON, and
359371responses *into* JSON. (JSON is just the running example - you can do this with
360372any content-type.)
361373
362−This section introduces a couple of typeclasses provided by **servant** that make
374+This section introduces a couple of typeclasses provided by *servant* that make
363375all of this work.
364376
365377### The truth behind `JSON`
366378
367379
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.
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.
371382
372383``` haskell ignore
373384data JSON
@@ -377,15 +388,14 @@ data OctetStream
377388```
378389
379390Obviously, this is not all there is to `JSON`, otherwise it would be quite
380−pointless. Like most of the data types in **servant**, `JSON` is mostly there as
391+pointless. Like most of the data types in *servant*, `JSON` is mostly there as
381392a special *symbol* that's associated with encoding (resp. decoding) to (resp.
382393from) the *JSON* format. The way this association is performed can be
383394decomposed into two steps.
384395
385396The first step is to provide a proper
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
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
389399haddocks from this link, you can see that we just have to specify
390400`application/json` using the appropriate functions. In our case, we can just
391401use `(//) :: ByteString -> ByteString -> MediaType`. The precise way to specify
@@ -401,14 +411,14 @@ instance Accept JSON where
401411```
402412
403413The second step is centered around the `MimeRender` and `MimeUnrender` classes.
404−These classes just let you specify a way to encode and decode
405−values into or from your content-type's representation.
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.
406416
407417``` haskell ignore
408418class Accept ctype => MimeRender ctype a where
409− mimeRender :: Proxy ctype -> a -> ByteString
419+ mimeRender :: Proxy ctype -> a -> ByteString
410420 -- alternatively readable as:
411− mimeRender :: Proxy ctype -> (a -> ByteString)
421+ mimeRender :: Proxy ctype -> (a -> ByteString)
412422```
413423
414424Given a content-type and some user type, `MimeRender` provides a function that
@@ -434,7 +444,7 @@ class Accept ctype => MimeUnrender ctype a where
434444We don't have much work to do there either, `Data.Aeson.eitherDecode` is
435445precisely what we need. However, it only allows arrays and objects as toplevel
436446JSON values and this has proven to get in our way more than help us so we wrote
437−our own little function around **aeson** and **attoparsec** that allows any type of
447+our own little function around *aeson* and *attoparsec* that allows any type of
438448JSON value at the toplevel of a "JSON document". Here's the definition in case
439449you are curious.
440450
@@ -452,20 +462,20 @@ instance FromJSON a => MimeUnrender JSON a where
452462 mimeUnrender _ = eitherDecodeLenient
453463```
454464
455−And this is all the code that lets you use `JSON` with `ReqBody`, `Get`,
465+And this is all the code that lets you use `JSON` for with `ReqBody`, `Get`,
456466`Post` and friends. We can check our understanding by implementing support
457−for an `HTML` content-type, so that users of your webservice can access an
467+for an `HTML` content type, so that users of your webservice can access an
458468HTML representation of the data they want, ready to be included in any HTML
459469document, e.g. using [jQuery's `load` function](https://api.jquery.com/load/),
460470simply by adding `Accept: text/html` to their request headers.
461471
462−### Case-studies: **servant-blaze** and **servant-lucid**
472+### Case-studies: *servant-blaze* and *servant-lucid*
463473
464474These days, most of the haskellers who write their HTML UIs directly from
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**:
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!).
469479
470480``` haskell
471481data HTMLLucid
@@ -473,20 +483,24 @@ data HTMLLucid
473483
474484Once again, the data type is just there as a symbol for the encoding/decoding
475485functions, except that this time we will only worry about encoding since
476−**lucid** doesn't provide a way to extract data from HTML.
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.
477489
478490``` haskell
479491instance Accept HTMLLucid where
480492 contentType _ = "text" // "html" /: ("charset", "utf-8")
481493```
482494
483−Note that this instance uses the `(/:)` operator from **http-media** which lets
495+Note that this instance uses the `(/:)` operator from *http-media* which lets
484496us specify additional information about a content-type, like the charset here.
485497
486−The rendering instances call similar functions that take
498+The rendering instances for both packages both call similar functions that take
487499types with an appropriate instance to an "abstract" HTML representation and
488500then write that to a `ByteString`.
489501
502+For *lucid*:
503+
490504``` haskell
491505instance ToHtml a => MimeRender HTMLLucid a where
492506 mimeRender _ = renderBS . toHtml
@@ -497,7 +511,7 @@ instance MimeRender HTMLLucid (Html a) where
497511 mimeRender _ = renderBS
498512```
499513
500−For **blaze-html** everything works very similarly:
514+For *blaze-html*:
501515
502516``` haskell
503517-- For this tutorial to compile 'HTMLLucid' and 'HTMLBlaze' have to be
@@ -517,13 +531,15 @@ instance MimeRender HTMLBlaze Text.Blaze.Html.Html where
517531 mimeRender _ = renderHtml
518532```
519533
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**).
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.
524541
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:
542+We will be serving the following API:
527543
528544``` haskell
529545type PersonAPI = "persons" :> Get '[JSON, HTMLLucid] [Person]
@@ -540,7 +556,7 @@ data Person = Person
540556instance ToJSON Person
541557```
542558
543−Now, let's teach **lucid** how to render a `Person` as a row in a table, and then
559+Now, let's teach *lucid* how to render a `Person` as a row in a table, and then
544560a list of `Person`s as a table with a row per person.
545561
546562``` haskell
@@ -584,45 +600,48 @@ server4 :: Server PersonAPI
584600server4 = return people
585601
586602app2 :: Application
587−app2 = serve personAPI server4
603+app2 = serve personAPI EmptyConfig server4
588604```
589605
590−And we're good to go:
606+And we're good to go. You can run this example with `dist/build/tutorial/tutorial 4`.
591607
592608``` bash
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
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
598614```
599615
600−## The `Handler` monad
616+## The `ExceptT ServantErr IO` monad
601617
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
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
605620simplest monad with the following properties:
606621
607−- it lets us both return a successful result (using `return`)
608−or "fail" with a descriptive error (using `throwError`);
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`);
609625- it lets us perform IO, which is absolutely vital since most webservices exist
610−as interfaces to databases that we interact with in `IO`.
626+as interfaces to databases that we interact with in `IO`;
611627
612628Let's recall some definitions.
613629
614630``` haskell ignore
631+-- from the Prelude
632+data Either e a = Left e | Right a
633+
615634-- from the 'mtl' package at
616−newtype ExceptT e m a = ExceptT (m (Either e a))
635+newtype ExceptT e m a = ExceptT ( m (Either e a) )
617636```
618637
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
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
621640action that either returns an error or a result.
622641
623−The module [`Control.Monad.Except`](https://hackage.haskell.org/package/mtl/docs/Control-Monad-Except.html#t:ExceptT)
642+The module [`Control.Monad.Except`](https://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#t:ExceptT)
624643from which `ExceptT` comes is worth looking at.
625−Perhaps most importantly, `ExceptT` and `Handler` are instances of `MonadError`, so
644+Perhaps most importantly, `ExceptT` is an instance of `MonadError`, so
626645`throwError` can be used to return an error from your handler (whereas `return`
627646 is enough to return a success).
628647
@@ -632,17 +651,18 @@ kind and abort early. The next two sections cover how to do just that.
632651
633652### Performing IO
634653
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:
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:
639658
640659``` haskell ignore
641660class Monad m => MonadIO m where
642661 liftIO :: IO a -> m a
643662```
644663
645−So if you want to run any kind of
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
646666IO computation in your handlers, just use `liftIO`:
647667
648668``` haskell
@@ -660,16 +680,16 @@ server5 = do
660680 return (FileContent filecontent)
661681```
662682
663−### Failing, through `ServerError`
683+### Failing, through `ServantErr`
664684
665685If you want to explicitly fail at providing the result promised by an endpoint
666686using the appropriate HTTP status code (not found, unauthorized, etc) and some
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
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
669689defined as:
670690
671691``` haskell ignore
672−data ServerError = ServerError
692+data ServantErr = ServantErr
673693 { errHTTPCode :: Int
674694 , errReasonPhrase :: String
675695 , errBody :: ByteString -- lazy bytestring
@@ -682,10 +702,10 @@ module. If you want to use these values but add a body or some headers, just
682702use record update syntax:
683703
684704``` haskell
685−failingHandler :: Handler ()
686−failingHandler = throwError myerr
705+failingHandler :: ExceptT ServantErr IO ()
706+failingHandler = throwE myerr
687707
688− where myerr :: ServerError
708+ where myerr :: ServantErr
689709 myerr = err503 { errBody = "Sorry dear user." }
690710```
691711
@@ -698,41 +718,42 @@ server6 = do
698718 exists <- liftIO (doesFileExist "myfile.txt")
699719 if exists
700720 then liftIO (readFile "myfile.txt") >>= return . FileContent
701− else throwError custom404Err
721+ else throwE custom404Err
702722
703723 where custom404Err = err404 { errBody = "myfile.txt just isn't there, please leave this server alone." }
704724```
705725
706−Here's how that server looks in action:
726+Let's run this server (`dist/build/tutorial/tutorial 5`) and
727+query it, first without the file and then with the file.
707728
708729``` bash
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"}
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"}
736757```
737758
738759## Response headers
@@ -748,77 +769,151 @@ myHandler :: Server MyHandler
748769myHandler = return $ addHeader 1797 albert
749770```
750771
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−```
772+Note that the type of `addHeader x` is different than the type of `x`!
774773
775774## Serving static files
776775
777−**servant-server** also provides a way to just serve the content of a directory
776+*servant-server* also provides a way to just serve the content of a directory
778777under some path in your web API. As mentioned earlier in this document, the
779778`Raw` combinator can be used in your APIs to mean "plug here any WAI
780−application". Well, **servant-server** provides a function to get a file and
779+application". Well, servant-server provides a function to get a file and
781780directory serving WAI application, namely:
782781
783782``` haskell ignore
784783-- exported by Servant and Servant.Server
785−serveDirectoryWebApp :: FilePath -> Server Raw
784+serveDirectory :: FilePath -> Server Raw
786785```
787786
788−`serveDirectoryWebApp`'s argument must be a path to a valid directory.
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.
789792
790−Here's an example API that will serve some static files:
793+The API type will be the following.
791794
792795``` haskell
793−type StaticAPI = "static" :> Raw
796+type CodeAPI = "code" :> Raw
794797```
795798
796799And the server:
797800
798801``` haskell
799−staticAPI :: Proxy StaticAPI
800−staticAPI = Proxy
802+codeAPI :: Proxy CodeAPI
803+codeAPI = Proxy
801804```
802805
803806``` haskell
804−server7 :: Server StaticAPI
805−server7 = serveDirectoryWebApp "static-files"
807+server7 :: Server CodeAPI
808+server7 = serveDirectory "tutorial"
806809
807810app3 :: Application
808−app3 = serve staticAPI server7
811+app3 = serve codeAPI EmptyConfig server7
809812```
810813
811−This server will match any request whose path starts with `/static` and will look
814+This server will match any request whose path starts with `/code` and will look
812815for a file at the path described by the rest of the request path, inside the
813− *static-files/* directory of the path you run the program from.
816+ *tutorial/* directory of the path you run the program from.
817+
818+In other words:
819+
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+ ]
814864
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.
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
818901
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.
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+```
822917
823918## Nested APIs
824919
@@ -830,7 +925,7 @@ type UserAPI3 = -- view the user with given userid, in JSON
830925 Capture "userid" Int :> Get '[JSON] User
831926
832927 :<|> -- delete the user with given userid. empty response
833− Capture "userid" Int :> DeleteNoContent
928+ Capture "userid" Int :> Delete '[] ()
834929```
835930
836931We can instead factor out the `userid`:
@@ -838,7 +933,7 @@ We can instead factor out the `userid`:
838933``` haskell
839934type UserAPI4 = Capture "userid" Int :>
840935 ( Get '[JSON] User
841− :<|> DeleteNoContent
936+ :<|> Delete '[] ()
842937 )
843938```
844939
@@ -846,26 +941,26 @@ However, you have to be aware that this has an effect on the type of the
846941corresponding `Server`:
847942
848943``` haskell ignore
849−Server UserAPI3 = (Int -> Handler User)
850− :<|> (Int -> Handler NoContent)
944+Server UserAPI3 = (Int -> ExceptT ServantErr IO User)
945+ :<|> (Int -> ExceptT ServantErr IO ())
851946
852−Server UserAPI4 = Int -> ( Handler User
853− :<|> Handler NoContent
947+Server UserAPI4 = Int -> ( ExceptT ServantErr IO User
948+ :<|> ExceptT ServantErr IO ()
854949 )
855950```
856951
857952In the first case, each handler receives the *userid* argument. In the latter,
858953the whole `Server` takes the *userid* and has handlers that are just
859−computations in `Handler`, with no arguments. In other words:
954+computations in `ExceptT`, with no arguments. In other words:
860955
861956``` haskell
862957server8 :: Server UserAPI3
863958server8 = getUser :<|> deleteUser
864959
865− where getUser :: Int -> Handler User
960+ where getUser :: Int -> ExceptT ServantErr IO User
866961 getUser _userid = error "..."
867962
868− deleteUser :: Int -> Handler NoContent
963+ deleteUser :: Int -> ExceptT ServantErr IO ()
869964 deleteUser _userid = error "..."
870965
871966-- notice how getUser and deleteUser
@@ -874,10 +969,10 @@ server8 = getUser :<|> deleteUser
874969server9 :: Server UserAPI4
875970server9 userid = getUser userid :<|> deleteUser userid
876971
877− where getUser :: Int -> Handler User
972+ where getUser :: Int -> ExceptT ServantErr IO User
878973 getUser = error "..."
879974
880− deleteUser :: Int -> Handler NoContent
975+ deleteUser :: Int -> ExceptT ServantErr IO ()
881976 deleteUser = error "..."
882977```
883978
@@ -896,13 +991,13 @@ type API1 = "users" :>
896991-- we factor out the Request Body
897992type API2 = ReqBody '[JSON] User :>
898993 ( Get '[JSON] User -- just display the same user back, don't register it
899− :<|> PostNoContent -- register the user. empty response
994+ :<|> Post '[JSON] () -- register the user. empty response
900995 )
901996
902997-- we factor out a Header
903998type API3 = Header "Authorization" Token :>
904999 ( Get '[JSON] SecretData -- get some secret data, if authorized
905− :<|> ReqBody '[JSON] SecretData :> PostNoContent -- add some secret data, if authorized
1000+ :<|> ReqBody '[JSON] SecretData :> Post '[] () -- add some secret data, if authorized
9061001 )
9071002
9081003newtype Token = Token ByteString
@@ -915,44 +1010,44 @@ API type only at the end.
9151010``` haskell
9161011type UsersAPI =
9171012 Get '[JSON] [User] -- list users
918− :<|> ReqBody '[JSON] User :> PostNoContent -- add a user
1013+ :<|> ReqBody '[JSON] User :> Post '[] () -- add a user
9191014 :<|> Capture "userid" Int :>
9201015 ( Get '[JSON] User -- view a user
921− :<|> ReqBody '[JSON] User :> PutNoContent -- update a user
922− :<|> DeleteNoContent -- delete a user
1016+ :<|> ReqBody '[JSON] User :> Put '[] () -- update a user
1017+ :<|> Delete '[] () -- delete a user
9231018 )
9241019
9251020usersServer :: Server UsersAPI
9261021usersServer = getUsers :<|> newUser :<|> userOperations
9271022
928− where getUsers :: Handler [User]
1023+ where getUsers :: ExceptT ServantErr IO [User]
9291024 getUsers = error "..."
9301025
931− newUser :: User -> Handler NoContent
1026+ newUser :: User -> ExceptT ServantErr IO ()
9321027 newUser = error "..."
9331028
9341029 userOperations userid =
9351030 viewUser userid :<|> updateUser userid :<|> deleteUser userid
9361031
9371032 where
938− viewUser :: Int -> Handler User
1033+ viewUser :: Int -> ExceptT ServantErr IO User
9391034 viewUser = error "..."
9401035
941− updateUser :: Int -> User -> Handler NoContent
1036+ updateUser :: Int -> User -> ExceptT ServantErr IO ()
9421037 updateUser = error "..."
9431038
944− deleteUser :: Int -> Handler NoContent
1039+ deleteUser :: Int -> ExceptT ServantErr IO ()
9451040 deleteUser = error "..."
9461041```
9471042
9481043``` haskell
9491044type ProductsAPI =
9501045 Get '[JSON] [Product] -- list products
951− :<|> ReqBody '[JSON] Product :> PostNoContent -- add a product
1046+ :<|> ReqBody '[JSON] Product :> Post '[] () -- add a product
9521047 :<|> Capture "productid" Int :>
9531048 ( Get '[JSON] Product -- view a product
954− :<|> ReqBody '[JSON] Product :> PutNoContent -- update a product
955− :<|> DeleteNoContent -- delete a product
1049+ :<|> ReqBody '[JSON] Product :> Put '[] () -- update a product
1050+ :<|> Delete '[] () -- delete a product
9561051 )
9571052
9581053data Product = Product { productId :: Int }
@@ -960,23 +1055,23 @@ data Product = Product { productId :: Int }
9601055productsServer :: Server ProductsAPI
9611056productsServer = getProducts :<|> newProduct :<|> productOperations
9621057
963− where getProducts :: Handler [Product]
1058+ where getProducts :: ExceptT ServantErr IO [Product]
9641059 getProducts = error "..."
9651060
966− newProduct :: Product -> Handler NoContent
1061+ newProduct :: Product -> ExceptT ServantErr IO ()
9671062 newProduct = error "..."
9681063
9691064 productOperations productid =
9701065 viewProduct productid :<|> updateProduct productid :<|> deleteProduct productid
9711066
9721067 where
973− viewProduct :: Int -> Handler Product
1068+ viewProduct :: Int -> ExceptT ServantErr IO Product
9741069 viewProduct = error "..."
9751070
976− updateProduct :: Int -> Product -> Handler NoContent
1071+ updateProduct :: Int -> Product -> ExceptT ServantErr IO ()
9771072 updateProduct = error "..."
9781073
979− deleteProduct :: Int -> Handler NoContent
1074+ deleteProduct :: Int -> ExceptT ServantErr IO ()
9801075 deleteProduct = error "..."
9811076```
9821077
@@ -996,49 +1091,39 @@ abstract that away:
9961091-- indexed by values of type 'i'
9971092type APIFor a i =
9981093 Get '[JSON] [a] -- list 'a's
999− :<|> ReqBody '[JSON] a :> PostNoContent -- add an 'a'
1094+ :<|> ReqBody '[JSON] a :> Post '[] () -- add an 'a'
10001095 :<|> Capture "id" i :>
10011096 ( Get '[JSON] a -- view an 'a' given its "identifier" of type 'i'
1002− :<|> ReqBody '[JSON] a :> PutNoContent -- update an 'a'
1003− :<|> DeleteNoContent -- delete an 'a'
1097+ :<|> ReqBody '[JSON] a :> Put '[] () -- update an 'a'
1098+ :<|> Delete '[] () -- delete an 'a'
10041099 )
10051100
10061101-- Build the appropriate 'Server'
10071102-- given the handlers of the right type.
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
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
10131108 -> Server (APIFor a i)
10141109serverFor = error "..."
10151110-- implementation left as an exercise. contact us on IRC
10161111-- or the mailing list if you get stuck!
10171112```
10181113
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−
10301114## Using another monad for your handlers
10311115
1032−Remember how `Server` turns combinators for HTTP methods into `Handler`? Well, actually, there's more to that. `Server` is actually a
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
10331118simple type synonym.
10341119
10351120``` haskell ignore
1036−type Server api = ServerT api Handler
1121+type Server api = ServerT api (ExceptT ServantErr IO)
10371122```
10381123
10391124`ServerT` is the actual type family that computes the required types for the
10401125handlers 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,
1126+it takes a third parameter which is the monad you want your handlers to run in,
10421127or more generally the return types of your handlers. This third parameter is
10431128used for specifying the return type of the handler for an endpoint, e.g when
10441129computing `ServerT (Get '[JSON] Person) SomeMonad`. The result would be
@@ -1046,155 +1131,98 @@ computing `ServerT (Get '[JSON] Person) SomeMonad`. The result would be
10461131
10471132The first and main question one might have then is: how do we write handlers
10481133that run in another monad? How can we "bring back" the value from a given monad
1049−into something **servant** can understand?
1134+into something *servant* can understand?
10501135
10511136### Natural transformations
10521137
10531138If we have a function that gets us from an `m a` to an `n a`, for any `a`, what
10541139do we have?
10551140
1056−``` haskell
1057−type (~>) m n = forall a. m a -> n a
1058−```
1059−
1060−For example:
1141+``` haskell ignore
1142+newtype m :~> n = Nat { unNat :: forall a. m a -> n a}
10611143
1062−``` haskell
1063−listToMaybe' :: [] ~> Maybe
1064−listToMaybe' = listToMaybe -- from Data.Maybe
1144+-- For example
1145+-- listToMaybeNat ::`[] :~> Maybe`
1146+-- listToMaybeNat = Nat listToMaybe -- from Data.Maybe
10651147```
1148+(`Nat` comes from "natural transformation", in case you're wondering.)
10661149
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
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
10711152prepare is a function:
10721153
10731154``` haskell ignore
1074−readerToHandler :: Reader String a -> Handler a
1155+readerToEither :: Reader String :~> ExceptT ServantErr IO
10751156```
10761157
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`.
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.
10801162
10811163``` haskell
1082−readerToHandler :: Reader String a -> Handler a
1083−readerToHandler r = return (runReader r "hi")
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'
10841169```
10851170
10861171We can write some simple webservice with the handlers running in `Reader String`.
10871172
10881173``` haskell
10891174type ReaderAPI = "a" :> Get '[JSON] Int
1090− :<|> "b" :> ReqBody '[JSON] Double :> Get '[JSON] Bool
1175+ :<|> "b" :> Get '[JSON] String
10911176
10921177readerAPI :: Proxy ReaderAPI
10931178readerAPI = Proxy
10941179
10951180readerServerT :: ServerT ReaderAPI (Reader String)
1096−readerServerT = a :<|> b where
1097− a :: Reader String Int
1098− a = return 1797
1181+readerServerT = a :<|> b
1182+
1183+ where a :: Reader String Int
1184+ a = return 1797
10991185
1100− b :: Double -> Reader String Bool
1101− b _ = asks (== "hi")
1186+ b :: Reader String String
1187+ b = ask
11021188```
11031189
11041190We unfortunately can't use `readerServerT` as an argument of `serve`, because
1105−`serve` wants a `Server ReaderAPI`, i.e., with handlers running in `Handler`. But there's a simple solution to this.
1191+`serve` wants a `Server ReaderAPI`, i.e., with handlers running in `ExceptT
1192+ServantErr IO`. But there's a simple solution to this.
11061193
1107−### Welcome `hoistServer`
1194+### Enter `enter`
11081195
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
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
11111198right type for `serve`. Being cumbersome to do by hand, we provide a function
1112−`hoistServer` which takes a natural transformation between two parameterized types `m`
1199+`enter` which takes a natural transformation between two parametrized types `m`
11131200and `n` and a `ServerT someapi m`, and returns a `ServerT someapi n`.
11141201
1115−In our case, we can wrap up our little webservice by using
1116−`hoistServer readerAPI readerToHandler` on our handlers.
1202+In our case, we can wrap up our little webservice by using `enter
1203+readerToEither` on our handlers.
11171204
11181205``` haskell
11191206readerServer :: Server ReaderAPI
1120−readerServer = hoistServer readerAPI readerToHandler readerServerT
1207+readerServer = enter readerToEither readerServerT
11211208
11221209app4 :: Application
1123−app4 = serve readerAPI readerServer
1210+app4 = serve readerAPI EmptyConfig readerServer
11241211```
11251212
1126−This is the webservice in action:
1213+And we can indeed see this webservice in action by running
1214+`dist/build/tutorial/tutorial 7`.
11271215
11281216``` bash
11291217$ curl http://localhost:8081/a
113012181797
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)
1219+$ curl http://localhost:8081/b
1220+"hi"
11601221```
11611222
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−
11961223## Conclusion
11971224
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**.
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*.