@@ -1,1200 +0,0 @@
1−# Serving an API
2−
3−Enough chit-chat about type-level combinators and representing an API as a
4−type. Can we have a webservice already?
5−
6−## A first example
7−
8−Equipped with some basic knowledge about the way we represent APIs, let's now
9−write our first webservice.
10−
11−The source for this tutorial section is a literate haskell file, so first we
12−need to have some language extensions and imports:
13−
14−``` haskell
15−{-# LANGUAGE DataKinds #-}
16−{-# LANGUAGE DeriveGeneric #-}
17−{-# LANGUAGE FlexibleInstances #-}
18−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
19−{-# LANGUAGE MultiParamTypeClasses #-}
20−{-# LANGUAGE OverloadedStrings #-}
21−{-# LANGUAGE RankNTypes #-}
22−{-# LANGUAGE ScopedTypeVariables #-}
23−{-# LANGUAGE TypeOperators #-}
24−
25−module Server where
26−
27−import Prelude ()
28−import Prelude.Compat
29−
30−import Control.Monad.Except
31−import Control.Monad.Reader
32−import Data.Aeson
33−import Data.Aeson.Types
34−import Data.Attoparsec.ByteString
35−import Data.ByteString (ByteString)
36−import Data.List
37−import Data.Maybe
38−import Data.String.Conversions
39−import Data.Time.Calendar
40−import GHC.Generics
41−import Lucid
42−import Network.HTTP.Media ((//), (/:))
43−import Network.Wai
44−import Network.Wai.Handler.Warp
45−import Servant
46−import System.Directory
47−import Text.Blaze
48−import Text.Blaze.Html.Renderer.Utf8
49−import Servant.Types.SourceT (source)
50−import qualified Data.Aeson.Parser
51−import qualified Text.Blaze.Html
52−```
53−
54−**Important**: the `Servant` module comes from the **servant-server** package,
55−the one that lets us run webservers that implement a particular API type. It
56−reexports all the types from the **servant** package that let you declare API
57−types as well as everything you need to turn your request handlers into a
58−fully-fledged webserver. This means that in your applications, you can just add
59−**servant-server** as a dependency, import `Servant` and not worry about anything
60−else.
61−
62−We will write a server that will serve the following API.
63−
64−``` haskell
65−type UserAPI1 = "users" :> Get '[JSON] [User]
66−```
67−
68−Here's what we would like to see when making a GET request to `/users`.
69−
70−``` javascript
71−[ {"name": "Isaac Newton", "age": 372, "email": "isaac@newton.co.uk", "registration_date": "1683-03-01"}
72−, {"name": "Albert Einstein", "age": 136, "email": "ae@mc2.org", "registration_date": "1905-12-01"}
73−]
74−```
75−
76−Now let's define our `User` data type and write some instances for it.
77−
78−``` haskell
79−data User = User
80− { name :: String
81− , age :: Int
82− , email :: String
83− , registration_date :: Day
84− } deriving (Eq, Show, Generic)
85−
86−instance ToJSON User
87−```
88−
89−Nothing funny going on here. But we now can define our list of two users.
90−
91−``` haskell
92−users1 :: [User]
93−users1 =
94− [ User "Isaac Newton" 372 "isaac@newton.co.uk" (fromGregorian 1683 3 1)
95− , User "Albert Einstein" 136 "ae@mc2.org" (fromGregorian 1905 12 1)
96− ]
97−```
98−
99−We can now take care of writing the actual webservice that will handle requests
100−to such an API. This one will be very simple, being reduced to just a single
101−endpoint. The type of the web application is determined by the API type,
102−through a *type family* named `Server`. (Type families are just functions that
103−take types as input and return types.) The `Server` type family will compute
104−the right type that a bunch of request handlers should have just from the
105−corresponding API type.
106−
107−The first thing to know about the `Server` type family is that behind the
108−scenes it will drive the routing, letting you focus only on the business
109−logic. 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
111−easily, as explained near the end of this guide. Third thing, the type of the
112−value returned in that monad must be the same as the second argument of the
113−HTTP method combinator used for the corresponding endpoint. In our case, it
114−means we must provide a handler of type `Handler [User]`. Well,
115−we have a monad, let's just `return` our list:
116−
117−``` haskell
118−server1 :: Server UserAPI1
119−server1 = return users1
120−```
121−
122−That's it. Now we can turn `server` into an actual webserver using
123−[wai](http://hackage.haskell.org/package/wai) and
124−[warp](http://hackage.haskell.org/package/warp):
125−
126−``` haskell
127−userAPI :: Proxy UserAPI1
128−userAPI = Proxy
129−
130−-- 'serve' comes from servant and hands you a WAI Application,
131−-- which you can think of as an "abstract" web application,
132−-- not yet a webserver.
133−app1 :: Application
134−app1 = serve userAPI server1
135−```
136−
137−The `userAPI` bit is, alas, boilerplate (we need it to guide type inference).
138−But that's about as much boilerplate as you get.
139−
140−And we're done! Let's run our webservice on the port 8081.
141−
142−``` haskell
143−main :: IO ()
144−main = run 8081 app1
145−```
146−
147−You can put this all into a file or just grab [servant's
148−repo](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*.
151−
152−If you run it, you can go to `http://localhost:8081/users` in your browser or
153−query it with curl and you see:
154−
155−``` bash
156−$ curl http://localhost:8081/users
157−[{"email":"isaac@newton.co.uk","registration_date":"1683-03-01","age":372,"name":"Isaac Newton"},{"email":"ae@mc2.org","registration_date":"1905-12-01","age":136,"name":"Albert Einstein"}]
158−```
159−
160−## More endpoints
161−
162−What if we want more than one endpoint? Let's add `/albert` and `/isaac` to
163−view the corresponding users encoded in JSON.
164−
165−``` haskell
166−type UserAPI2 = "users" :> Get '[JSON] [User]
167− :<|> "albert" :> Get '[JSON] User
168− :<|> "isaac" :> Get '[JSON] User
169−```
170−
171−And let's adapt our code a bit.
172−
173−``` haskell
174−isaac :: User
175−isaac = User "Isaac Newton" 372 "isaac@newton.co.uk" (fromGregorian 1683 3 1)
176−
177−albert :: User
178−albert = User "Albert Einstein" 136 "ae@mc2.org" (fromGregorian 1905 12 1)
179−
180−users2 :: [User]
181−users2 = [isaac, albert]
182−```
183−
184−Now, just like we separate the various endpoints in `UserAPI` with `:<|>`, we
185−are going to separate the handlers with `:<|>` too! They must be provided in
186−the same order as in the API type.
187−
188−``` haskell
189−server2 :: Server UserAPI2
190−server2 = return users2
191− :<|> return albert
192− :<|> return isaac
193−```
194−
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`.
197−
198−## From combinators to handler arguments
199−
200−Fine, we can write trivial webservices easily, but none of the two above use
201−any "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
203−combinators in an endpoint makes the corresponding handler receive an
204−argument of the appropriate type automatically. You don't have to worry about
205−manually looking up URL captures or query string parameters, or
206−decoding/encoding data from/to JSON. Never.
207−
208−We are going to use the following data types and functions to implement a
209−server for `API`.
210−
211−``` haskell
212−type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
213− :<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
214− :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email
215−
216−data Position = Position
217− { xCoord :: Int
218− , yCoord :: Int
219− } deriving Generic
220−
221−instance ToJSON Position
222−
223−newtype HelloMessage = HelloMessage { msg :: String }
224− deriving Generic
225−
226−instance ToJSON HelloMessage
227−
228−data ClientInfo = ClientInfo
229− { clientName :: String
230− , clientEmail :: String
231− , clientAge :: Int
232− , clientInterestedIn :: [String]
233− } deriving Generic
234−
235−instance FromJSON ClientInfo
236−instance ToJSON ClientInfo
237−
238−data Email = Email
239− { from :: String
240− , to :: String
241− , subject :: String
242− , body :: String
243− } deriving Generic
244−
245−instance ToJSON Email
246−
247−emailForClient :: ClientInfo -> Email
248−emailForClient c = Email from' to' subject' body'
249−
250− where from' = "great@company.com"
251− to' = clientEmail c
252− subject' = "Hey " ++ clientName c ++ ", we miss you!"
253− body' = "Hi " ++ clientName c ++ ",\n\n"
254− ++ "Since you've recently turned " ++ show (clientAge c)
255− ++ ", have you checked out our latest "
256− ++ intercalate ", " (clientInterestedIn c)
257− ++ " products? Give us a visit!"
258−```
259−
260−We can implement handlers for the three endpoints:
261−
262−``` haskell
263−server3 :: Server API
264−server3 = position
265− :<|> hello
266− :<|> marketing
267−
268− where position :: Int -> Int -> Handler Position
269− position x y = return (Position x y)
270−
271− hello :: Maybe String -> Handler HelloMessage
272− hello mname = return . HelloMessage $ case mname of
273− Nothing -> "Hello, anonymous coward"
274− Just n -> "Hello, " ++ n
275−
276− marketing :: ClientInfo -> Handler Email
277− marketing clientinfo = return (emailForClient clientinfo)
278−```
279−
280−Did you see that? The types for your handlers changed to be just what we
281−needed! In particular:
282−
283− - a `Capture "something" a` becomes an argument of type `a` (for `position`);
284− - a `QueryParam "something" a` becomes an argument of type `Maybe a` (because
285−an endpoint can technically be accessed without specifying any query
286−string parameter, we decided to "force" handlers to be aware that the
287−parameter might not always be there);
288−
289− - a `ReqBody contentTypeList a` becomes an argument of type `a`;
290−
291−And that's it. Here's the example in action:
292−
293−``` bash
294−$ curl http://localhost:8081/position/1/2
295−{"xCoord":1,"yCoord":2}
296−$ curl http://localhost:8081/hello
297−{"msg":"Hello, anonymous coward"}
298−$ curl http://localhost:8081/hello?name=Alp
299−{"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
301−{"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"}
302−```
303−
304−For reference, here's a list of some combinators from **servant**:
305−
306− > - `Delete`, `Get`, `Patch`, `Post`, `Put`: these do not become arguments. They provide the return type of handlers, which usually is `Handler <something>`.
307− > - `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]`.
311− > - `ReqBody contentTypes a` gets turned into an argument of type `a`.
312−
313−## The `FromHttpApiData`/`ToHttpApiData` classes
314−
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.
318−
319−`Capture`s and `QueryParam`s are represented by some textual value in URLs.
320−`Header`s are similarly represented by a pair of a header name and a
321−corresponding (textual) value in the request's "metadata". How types are
322−decoded from headers, captures, and query params is expressed in a class
323−`FromHttpApiData` (from the package
324−[**http-api-data**](http://hackage.haskell.org/package/http-api-data)):
325−
326−``` haskell ignore
327−class FromHttpApiData a where
328− {-# MINIMAL parseUrlPiece | parseQueryParam #-}
329− -- | Parse URL path piece.
330− parseUrlPiece :: Text -> Either Text a
331− parseUrlPiece = parseQueryParam
332−
333− -- | Parse HTTP header value.
334− parseHeader :: ByteString -> Either Text a
335− parseHeader = parseUrlPiece . decodeUtf8
336−
337− -- | Parse query param value.
338− parseQueryParam :: Text -> Either Text a
339− parseQueryParam = parseUrlPiece
340−```
341−
342−As you can see, as long as you provide either `parseUrlPiece` (for `Capture`s)
343−or `parseQueryParam` (for `QueryParam`s), the other methods will be defined in
344−terms of this.
345−
346−**http-api-data** provides a decent number of instances, helpers for defining new
347−ones, and wonderful documentation.
348−
349−There's not much else to say about these classes. You will need instances for
350−them when using `Capture`, `QueryParam`, `QueryParams`, and `Header` with your
351−types. You will need `FromHttpApiData` instances for server-side request
352−handlers and `ToHttpApiData` instances only when using
353−**servant-client**, as described in the [section about deriving haskell
354−functions to query an API](Client.html).
355−
356−## Using content-types with your data types
357−
358−The same principle was operating when decoding request bodies from JSON, and
359−responses *into* JSON. (JSON is just the running example - you can do this with
360−any content-type.)
361−
362−This section introduces a couple of typeclasses provided by **servant** that make
363−all of this work.
364−
365−### The truth behind `JSON`
366−
367−
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.
371−
372−``` haskell ignore
373−data JSON
374−data PlainText
375−data FormUrlEncoded
376−data OctetStream
377−```
378−
379−Obviously, 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
381−a special *symbol* that's associated with encoding (resp. decoding) to (resp.
382−from) the *JSON* format. The way this association is performed can be
383−decomposed into two steps.
384−
385−The 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
389−haddocks from this link, you can see that we just have to specify
390−`application/json` using the appropriate functions. In our case, we can just
391−use `(//) :: ByteString -> ByteString -> MediaType`. The precise way to specify
392−the `MediaType` is to write an instance for the `Accept` class:
393−
394−``` haskell ignore
395−-- for reference:
396−class Accept ctype where
397− contentType :: Proxy ctype -> MediaType
398−
399−instance Accept JSON where
400− contentType _ = "application" // "json"
401−```
402−
403−The 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.
406−
407−``` haskell ignore
408−class Accept ctype => MimeRender ctype a where
409− mimeRender :: Proxy ctype -> a -> ByteString
410− -- alternatively readable as:
411− mimeRender :: Proxy ctype -> (a -> ByteString)
412−```
413−
414−Given a content-type and some user type, `MimeRender` provides a function that
415−encodes values of type `a` to lazy `ByteString`s.
416−
417−In the case of `JSON`, this is easily dealt with! For any type `a` with a
418−`ToJSON` instance, we can render values of that type to JSON using
419−`Data.Aeson.encode`.
420−
421−``` haskell ignore
422−instance ToJSON a => MimeRender JSON a where
423− mimeRender _ = encode
424−```
425−
426−And now the `MimeUnrender` class, which lets us extract values from lazy
427−`ByteString`s, alternatively failing with an error string.
428−
429−``` haskell ignore
430−class Accept ctype => MimeUnrender ctype a where
431− mimeUnrender :: Proxy ctype -> ByteString -> Either String a
432−```
433−
434−We don't have much work to do there either, `Data.Aeson.eitherDecode` is
435−precisely what we need. However, it only allows arrays and objects as toplevel
436−JSON 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
438−JSON value at the toplevel of a "JSON document". Here's the definition in case
439−you are curious.
440−
441−``` haskell
442−eitherDecodeLenient :: FromJSON a => ByteString -> Either String a
443−eitherDecodeLenient input = do
444− v :: Value <- parseOnly (Data.Aeson.Parser.value <* endOfInput) (cs input)
445− parseEither parseJSON v
446−```
447−
448−This function is exactly what we need for our `MimeUnrender` instance.
449−
450−``` haskell ignore
451−instance FromJSON a => MimeUnrender JSON a where
452− mimeUnrender _ = eitherDecodeLenient
453−```
454−
455−And this is all the code that lets you use `JSON` with `ReqBody`, `Get`,
456−`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
458−HTML representation of the data they want, ready to be included in any HTML
459−document, e.g. using [jQuery's `load` function](https://api.jquery.com/load/),
460−simply by adding `Accept: text/html` to their request headers.
461−
462−### Case-studies: **servant-blaze** and **servant-lucid**
463−
464−These 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**:
469−
470−``` haskell
471−data HTMLLucid
472−```
473−
474−Once again, the data type is just there as a symbol for the encoding/decoding
475−functions, except that this time we will only worry about encoding since
476−**lucid** doesn't provide a way to extract data from HTML.
477−
478−``` haskell
479−instance Accept HTMLLucid where
480− contentType _ = "text" // "html" /: ("charset", "utf-8")
481−```
482−
483−Note that this instance uses the `(/:)` operator from **http-media** which lets
484−us specify additional information about a content-type, like the charset here.
485−
486−The rendering instances call similar functions that take
487−types with an appropriate instance to an "abstract" HTML representation and
488−then write that to a `ByteString`.
489−
490−``` haskell
491−instance ToHtml a => MimeRender HTMLLucid a where
492− mimeRender _ = renderBS . toHtml
493−
494−-- let's also provide an instance for lucid's
495−-- 'Html' wrapper.
496−instance MimeRender HTMLLucid (Html a) where
497− mimeRender _ = renderBS
498−```
499−
500−For **blaze-html** everything works very similarly:
501−
502−``` haskell
503−-- For this tutorial to compile 'HTMLLucid' and 'HTMLBlaze' have to be
504−-- distinct. Usually you would stick to one html rendering library and then
505−-- you can go with one 'HTML' type.
506−data HTMLBlaze
507−
508−instance Accept HTMLBlaze where
509− contentType _ = "text" // "html" /: ("charset", "utf-8")
510−
511−instance ToMarkup a => MimeRender HTMLBlaze a where
512− mimeRender _ = renderHtml . Text.Blaze.Html.toHtml
513−
514−-- while we're at it, just like for lucid we can
515−-- provide an instance for rendering blaze's 'Html' type
516−instance MimeRender HTMLBlaze Text.Blaze.Html.Html where
517− mimeRender _ = renderHtml
518−```
519−
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**).
524−
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:
527−
528−``` haskell
529−type PersonAPI = "persons" :> Get '[JSON, HTMLLucid] [Person]
530−```
531−
532−where `Person` is defined as follows:
533−
534−``` haskell
535−data Person = Person
536− { firstName :: String
537− , lastName :: String
538− } deriving Generic -- for the JSON instance
539−
540−instance ToJSON Person
541−```
542−
543−Now, let's teach **lucid** how to render a `Person` as a row in a table, and then
544−a list of `Person`s as a table with a row per person.
545−
546−``` haskell
547−-- HTML serialization of a single person
548−instance ToHtml Person where
549− toHtml person =
550− tr_ $ do
551− td_ (toHtml $ firstName person)
552− td_ (toHtml $ lastName person)
553−
554− -- do not worry too much about this
555− toHtmlRaw = toHtml
556−
557−-- HTML serialization of a list of persons
558−instance ToHtml [Person] where
559− toHtml persons = table_ $ do
560− tr_ $ do
561− th_ "first name"
562− th_ "last name"
563−
564− -- this just calls toHtml on each person of the list
565− -- and concatenates the resulting pieces of HTML together
566− foldMap toHtml persons
567−
568− toHtmlRaw = toHtml
569−```
570−
571−We create some `Person` values and serve them as a list:
572−
573−``` haskell
574−people :: [Person]
575−people =
576− [ Person "Isaac" "Newton"
577− , Person "Albert" "Einstein"
578− ]
579−
580−personAPI :: Proxy PersonAPI
581−personAPI = Proxy
582−
583−server4 :: Server PersonAPI
584−server4 = return people
585−
586−app2 :: Application
587−app2 = serve personAPI server4
588−```
589−
590−And we're good to go:
591−
592−``` 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
598−```
599−
600−## The `Handler` monad
601−
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
605−simplest monad with the following properties:
606−
607−- it lets us both return a successful result (using `return`)
608−or "fail" with a descriptive error (using `throwError`);
609−- it lets us perform IO, which is absolutely vital since most webservices exist
610−as interfaces to databases that we interact with in `IO`.
611−
612−Let's recall some definitions.
613−
614−``` haskell ignore
615−-- from the 'mtl' package at
616−newtype ExceptT e m a = ExceptT (m (Either e a))
617−```
618−
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
621−action that either returns an error or a result.
622−
623−The module [`Control.Monad.Except`](https://hackage.haskell.org/package/mtl/docs/Control-Monad-Except.html#t:ExceptT)
624−from which `ExceptT` comes is worth looking at.
625−Perhaps most importantly, `ExceptT` and `Handler` are instances of `MonadError`, so
626−`throwError` can be used to return an error from your handler (whereas `return`
627− is enough to return a success).
628−
629−Most of what you'll be doing in your handlers is running some IO and,
630−depending on the result, you might sometimes want to throw an error of some
631−kind and abort early. The next two sections cover how to do just that.
632−
633−### Performing IO
634−
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:
639−
640−``` haskell ignore
641−class Monad m => MonadIO m where
642− liftIO :: IO a -> m a
643−```
644−
645−So if you want to run any kind of
646−IO computation in your handlers, just use `liftIO`:
647−
648−``` haskell
649−type IOAPI1 = "myfile.txt" :> Get '[JSON] FileContent
650−
651−newtype FileContent = FileContent
652− { content :: String }
653− deriving Generic
654−
655−instance ToJSON FileContent
656−
657−server5 :: Server IOAPI1
658−server5 = do
659− filecontent <- liftIO (readFile "myfile.txt")
660− return (FileContent filecontent)
661−```
662−
663−### Failing, through `ServerError`
664−
665−If you want to explicitly fail at providing the result promised by an endpoint
666−using 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
669−defined as:
670−
671−``` haskell ignore
672−data ServerError = ServerError
673− { errHTTPCode :: Int
674− , errReasonPhrase :: String
675− , errBody :: ByteString -- lazy bytestring
676− , errHeaders :: [Header]
677− }
678−```
679−
680−Many standard values are provided out of the box by the `Servant.Server`
681−module. If you want to use these values but add a body or some headers, just
682−use record update syntax:
683−
684−``` haskell
685−failingHandler :: Handler ()
686−failingHandler = throwError myerr
687−
688− where myerr :: ServerError
689− myerr = err503 { errBody = "Sorry dear user." }
690−```
691−
692−Here's an example where we return a customised 404-Not-Found error message in
693−the response body if "myfile.txt" isn't there:
694−
695−``` haskell
696−server6 :: Server IOAPI1
697−server6 = do
698− exists <- liftIO (doesFileExist "myfile.txt")
699− if exists
700− then liftIO (readFile "myfile.txt") >>= return . FileContent
701− else throwError custom404Err
702−
703− where custom404Err = err404 { errBody = "myfile.txt just isn't there, please leave this server alone." }
704−```
705−
706−Here's how that server looks in action:
707−
708−``` 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"}
736−```
737−
738−## Response headers
739−
740−To add headers to your response, use
741−[addHeader](http://hackage.haskell.org/package/servant/docs/Servant-API-ResponseHeaders.html).
742−Note that this changes the type of your API, as we can see in the following example:
743−
744−``` haskell
745−type MyHandler = Get '[JSON] (Headers '[Header "X-An-Int" Int] User)
746−
747−myHandler :: Server MyHandler
748−myHandler = return $ addHeader 1797 albert
749−```
750−
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−```
774−
775−## Serving static files
776−
777−**servant-server** also provides a way to just serve the content of a directory
778−under some path in your web API. As mentioned earlier in this document, the
779−`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
781−directory serving WAI application, namely:
782−
783−``` haskell ignore
784−-- exported by Servant and Servant.Server
785−serveDirectoryWebApp :: FilePath -> Server Raw
786−```
787−
788−`serveDirectoryWebApp`'s argument must be a path to a valid directory.
789−
790−Here's an example API that will serve some static files:
791−
792−``` haskell
793−type StaticAPI = "static" :> Raw
794−```
795−
796−And the server:
797−
798−``` haskell
799−staticAPI :: Proxy StaticAPI
800−staticAPI = Proxy
801−```
802−
803−``` haskell
804−server7 :: Server StaticAPI
805−server7 = serveDirectoryWebApp "static-files"
806−
807−app3 :: Application
808−app3 = serve staticAPI server7
809−```
810−
811−This server will match any request whose path starts with `/static` and will look
812−for a file at the path described by the rest of the request path, inside the
813− *static-files/* directory of the path you run the program from.
814−
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.
818−
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.
822−
823−## Nested APIs
824−
825−Let's see how you can define APIs in a modular way, while avoiding repetition.
826−Consider this simple example:
827−
828−``` haskell
829−type UserAPI3 = -- view the user with given userid, in JSON
830− Capture "userid" Int :> Get '[JSON] User
831−
832− :<|> -- delete the user with given userid. empty response
833− Capture "userid" Int :> DeleteNoContent
834−```
835−
836−We can instead factor out the `userid`:
837−
838−``` haskell
839−type UserAPI4 = Capture "userid" Int :>
840− ( Get '[JSON] User
841− :<|> DeleteNoContent
842− )
843−```
844−
845−However, you have to be aware that this has an effect on the type of the
846−corresponding `Server`:
847−
848−``` haskell ignore
849−Server UserAPI3 = (Int -> Handler User)
850− :<|> (Int -> Handler NoContent)
851−
852−Server UserAPI4 = Int -> ( Handler User
853− :<|> Handler NoContent
854− )
855−```
856−
857−In the first case, each handler receives the *userid* argument. In the latter,
858−the whole `Server` takes the *userid* and has handlers that are just
859−computations in `Handler`, with no arguments. In other words:
860−
861−``` haskell
862−server8 :: Server UserAPI3
863−server8 = getUser :<|> deleteUser
864−
865− where getUser :: Int -> Handler User
866− getUser _userid = error "..."
867−
868− deleteUser :: Int -> Handler NoContent
869− deleteUser _userid = error "..."
870−
871−-- notice how getUser and deleteUser
872−-- have a different type! no argument anymore,
873−-- the argument directly goes to the whole Server
874−server9 :: Server UserAPI4
875−server9 userid = getUser userid :<|> deleteUser userid
876−
877− where getUser :: Int -> Handler User
878− getUser = error "..."
879−
880− deleteUser :: Int -> Handler NoContent
881− deleteUser = error "..."
882−```
883−
884−Note that there's nothing special about `Capture` that lets you "factor it
885−out": this can be done with any combinator. Here are a few examples of APIs
886−with a combinator factored out for which we can write a perfectly valid
887−`Server`.
888−
889−``` haskell
890−-- we just factor out the "users" path fragment
891−type API1 = "users" :>
892− ( Get '[JSON] [User] -- user listing
893− :<|> Capture "userid" Int :> Get '[JSON] User -- view a particular user
894− )
895−
896−-- we factor out the Request Body
897−type API2 = ReqBody '[JSON] User :>
898− ( Get '[JSON] User -- just display the same user back, don't register it
899− :<|> PostNoContent -- register the user. empty response
900− )
901−
902−-- we factor out a Header
903−type API3 = Header "Authorization" Token :>
904− ( Get '[JSON] SecretData -- get some secret data, if authorized
905− :<|> ReqBody '[JSON] SecretData :> PostNoContent -- add some secret data, if authorized
906− )
907−
908−newtype Token = Token ByteString
909−newtype SecretData = SecretData ByteString
910−```
911−
912−This approach lets you define APIs modularly and assemble them all into one big
913−API type only at the end.
914−
915−``` haskell
916−type UsersAPI =
917− Get '[JSON] [User] -- list users
918− :<|> ReqBody '[JSON] User :> PostNoContent -- add a user
919− :<|> Capture "userid" Int :>
920− ( Get '[JSON] User -- view a user
921− :<|> ReqBody '[JSON] User :> PutNoContent -- update a user
922− :<|> DeleteNoContent -- delete a user
923− )
924−
925−usersServer :: Server UsersAPI
926−usersServer = getUsers :<|> newUser :<|> userOperations
927−
928− where getUsers :: Handler [User]
929− getUsers = error "..."
930−
931− newUser :: User -> Handler NoContent
932− newUser = error "..."
933−
934− userOperations userid =
935− viewUser userid :<|> updateUser userid :<|> deleteUser userid
936−
937− where
938− viewUser :: Int -> Handler User
939− viewUser = error "..."
940−
941− updateUser :: Int -> User -> Handler NoContent
942− updateUser = error "..."
943−
944− deleteUser :: Int -> Handler NoContent
945− deleteUser = error "..."
946−```
947−
948−``` haskell
949−type ProductsAPI =
950− Get '[JSON] [Product] -- list products
951− :<|> ReqBody '[JSON] Product :> PostNoContent -- add a product
952− :<|> Capture "productid" Int :>
953− ( Get '[JSON] Product -- view a product
954− :<|> ReqBody '[JSON] Product :> PutNoContent -- update a product
955− :<|> DeleteNoContent -- delete a product
956− )
957−
958−data Product = Product { productId :: Int }
959−
960−productsServer :: Server ProductsAPI
961−productsServer = getProducts :<|> newProduct :<|> productOperations
962−
963− where getProducts :: Handler [Product]
964− getProducts = error "..."
965−
966− newProduct :: Product -> Handler NoContent
967− newProduct = error "..."
968−
969− productOperations productid =
970− viewProduct productid :<|> updateProduct productid :<|> deleteProduct productid
971−
972− where
973− viewProduct :: Int -> Handler Product
974− viewProduct = error "..."
975−
976− updateProduct :: Int -> Product -> Handler NoContent
977− updateProduct = error "..."
978−
979− deleteProduct :: Int -> Handler NoContent
980− deleteProduct = error "..."
981−```
982−
983−``` haskell
984−type CombinedAPI = "users" :> UsersAPI
985− :<|> "products" :> ProductsAPI
986−
987−server10 :: Server CombinedAPI
988−server10 = usersServer :<|> productsServer
989−```
990−
991−Finally, we can realize the user and product APIs are quite similar and
992−abstract that away:
993−
994−``` haskell
995−-- API for values of type 'a'
996−-- indexed by values of type 'i'
997−type APIFor a i =
998− Get '[JSON] [a] -- list 'a's
999− :<|> ReqBody '[JSON] a :> PostNoContent -- add an 'a'
1000− :<|> Capture "id" i :>
1001− ( 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'
1004− )
1005−
1006−-- Build the appropriate 'Server'
1007−-- 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
1013− -> Server (APIFor a i)
1014−serverFor = error "..."
1015−-- implementation left as an exercise. contact us on IRC
1016−-- or the mailing list if you get stuck!
1017−```
1018−
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−
1030−## Using another monad for your handlers
1031−
1032−Remember how `Server` turns combinators for HTTP methods into `Handler`? Well, actually, there's more to that. `Server` is actually a
1033−simple type synonym.
1034−
1035−``` haskell ignore
1036−type Server api = ServerT api Handler
1037−```
1038−
1039−`ServerT` is the actual type family that computes the required types for the
1040−handlers that's part of the `HasServer` class. It's like `Server` except that
1041−it takes another parameter which is the monad you want your handlers to run in,
1042−or more generally the return types of your handlers. This third parameter is
1043−used for specifying the return type of the handler for an endpoint, e.g when
1044−computing `ServerT (Get '[JSON] Person) SomeMonad`. The result would be
1045−`SomeMonad Person`.
1046−
1047−The first and main question one might have then is: how do we write handlers
1048−that run in another monad? How can we "bring back" the value from a given monad
1049−into something **servant** can understand?
1050−
1051−### Natural transformations
1052−
1053−If we have a function that gets us from an `m a` to an `n a`, for any `a`, what
1054−do we have?
1055−
1056−``` haskell
1057−type (~>) m n = forall a. m a -> n a
1058−```
1059−
1060−For example:
1061−
1062−``` haskell
1063−listToMaybe' :: [] ~> Maybe
1064−listToMaybe' = listToMaybe -- from Data.Maybe
1065−```
1066−
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
1071−prepare is a function:
1072−
1073−``` haskell ignore
1074−readerToHandler :: Reader String a -> Handler a
1075−```
1076−
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`.
1080−
1081−``` haskell
1082−readerToHandler :: Reader String a -> Handler a
1083−readerToHandler r = return (runReader r "hi")
1084−```
1085−
1086−We can write some simple webservice with the handlers running in `Reader String`.
1087−
1088−``` haskell
1089−type ReaderAPI = "a" :> Get '[JSON] Int
1090− :<|> "b" :> ReqBody '[JSON] Double :> Get '[JSON] Bool
1091−
1092−readerAPI :: Proxy ReaderAPI
1093−readerAPI = Proxy
1094−
1095−readerServerT :: ServerT ReaderAPI (Reader String)
1096−readerServerT = a :<|> b where
1097− a :: Reader String Int
1098− a = return 1797
1099−
1100− b :: Double -> Reader String Bool
1101− b _ = asks (== "hi")
1102−```
1103−
1104−We 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.
1106−
1107−### Welcome `hoistServer`
1108−
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
1111−right 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`
1113−and `n` and a `ServerT someapi m`, and returns a `ServerT someapi n`.
1114−
1115−In our case, we can wrap up our little webservice by using
1116−`hoistServer readerAPI readerToHandler` on our handlers.
1117−
1118−``` haskell
1119−readerServer :: Server ReaderAPI
1120−readerServer = hoistServer readerAPI readerToHandler readerServerT
1121−
1122−app4 :: Application
1123−app4 = serve readerAPI readerServer
1124−```
1125−
1126−This is the webservice in action:
1127−
1128−``` bash
1129−$ curl http://localhost:8081/a
1130−1797
1131−$ curl http://localhost:8081/b -X GET -d '42.0' -H 'Content-Type: application/json'
1132−true
1133−```
1134−
1135−### An arrow is a reader too.
1136−
1137−In previous versions of `servant` we had an `enter` to do what `hoistServer`
1138−does now. `enter` had an ambitious design goals, but was problematic in practice.
1139−
1140−One problematic situation was when the source monad was `(->) r`, yet it's
1141−handy in practice, because `(->) r` is isomorphic to `Reader r`.
1142−
1143−We can rewrite the previous example without `Reader`:
1144−
1145−```haskell
1146−funServerT :: ServerT ReaderAPI ((->) String)
1147−funServerT = a :<|> b where
1148− a :: String -> Int
1149− a _ = 1797
1150−
1151− -- unfortunately, we cannot make `String` the first argument.
1152− b :: Double -> String -> Bool
1153− b _ s = s == "hi"
1154−
1155−funToHandler :: (String -> a) -> Handler a
1156−funToHandler f = return (f "hi")
1157−
1158−app5 :: Application
1159−app5 = serve readerAPI (hoistServer readerAPI funToHandler funServerT)
1160−```
1161−
1162−## Streaming endpoints
1163−
1164−We can create endpoints that don't just give back a single result, but give
1165−back a *stream* of results, served one at a time. Stream endpoints only provide
1166−a single content type, and also specify what framing strategy is used to
1167−delineate the results. To serve these results, we need to give back a stream
1168−producer. Adapters can be written to *Pipes*, *Conduit* and the like, or
1169−written directly as `SourceIO`s. SourceIO builds upon servant's own `SourceT`
1170−stream type (it's simpler than *Pipes* or *Conduit*).
1171−The API of a streaming endpoint needs to explicitly specify which sort of
1172−generator it produces. Note that the generator itself is returned by a
1173−`Handler` action, so that additional IO may be done in the creation of one.
1174−
1175−``` haskell
1176−type StreamAPI = "userStream" :> StreamGet NewlineFraming JSON (SourceIO User)
1177−streamAPI :: Proxy StreamAPI
1178−streamAPI = Proxy
1179−
1180−streamUsers :: SourceIO User
1181−streamUsers = source [isaac, albert, albert]
1182−
1183−app6 :: Application
1184−app6 = serve streamAPI (return streamUsers)
1185−```
1186−
1187−This simple application returns a stream of `User` values encoded in JSON
1188−format, with each value separated by a newline. In this case, the stream will
1189−consist of the value of `isaac`, followed by the value of `albert`, then the
1190−value of `albert` a second time. Importantly, the stream is written back as
1191−results are produced, rather than all at once. This means first that results
1192−are delivered when they are available, and second, that if an exception
1193−interrupts production of the full stream, nonetheless partial results have
1194−already been written back.
1195−
1196−## Conclusion
1197−
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**.