git.iko.soy/typeable/servant
on master help sign in
Move tutorial files over
commit3b3c929b408a56e4cba4ca34d5a2dc9fa1486751 authorJulian K. Arni <jkarni@gmail.com> dateMon 25 Jan 2016, 14:11 (11 years ago) parent94e07f9
10 files changed+2622
.gitignore+1 tutorial/Makefile+216 tutorial/api-type.lhs+309 tutorial/client.lhs+138 tutorial/conf.py+287 tutorial/docs.lhs+227 tutorial/index.rst+68 tutorial/javascript.lhs+175 tutorial/requirements.txt+25 tutorial/server.lhs+1176
.gitignore+1
@@ -25,3 +25,4 @@ Setup
2525.stack-work
2626shell.nix
2727default.nix
28+tutorial/_build
tutorial/Makefilenew file+216
@@ -0,0 +1,216 @@
1+# Makefile for Sphinx documentation
2+#
3+
4+# You can set these variables from the command line.
5+SPHINXOPTS =
6+SPHINXBUILD = sphinx-build
7+PAPER =
8+BUILDDIR = _build
9+
10+# User-friendly check for sphinx-build
11+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
12+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
13+endif
14+
15+# Internal variables.
16+PAPEROPT_a4 = -D latex_paper_size=a4
17+PAPEROPT_letter = -D latex_paper_size=letter
18+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
19+# the i18n builder cannot share the environment and doctrees with the others
20+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
21+
22+.PHONY: help
23+help:
24+ @echo "Please use \`make <target>' where <target> is one of"
25+ @echo " html to make standalone HTML files"
26+ @echo " dirhtml to make HTML files named index.html in directories"
27+ @echo " singlehtml to make a single large HTML file"
28+ @echo " pickle to make pickle files"
29+ @echo " json to make JSON files"
30+ @echo " htmlhelp to make HTML files and a HTML help project"
31+ @echo " qthelp to make HTML files and a qthelp project"
32+ @echo " applehelp to make an Apple Help Book"
33+ @echo " devhelp to make HTML files and a Devhelp project"
34+ @echo " epub to make an epub"
35+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
36+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
37+ @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
38+ @echo " text to make text files"
39+ @echo " man to make manual pages"
40+ @echo " texinfo to make Texinfo files"
41+ @echo " info to make Texinfo files and run them through makeinfo"
42+ @echo " gettext to make PO message catalogs"
43+ @echo " changes to make an overview of all changed/added/deprecated items"
44+ @echo " xml to make Docutils-native XML files"
45+ @echo " pseudoxml to make pseudoxml-XML files for display purposes"
46+ @echo " linkcheck to check all external links for integrity"
47+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
48+ @echo " coverage to run coverage check of the documentation (if enabled)"
49+
50+.PHONY: clean
51+clean:
52+ rm -rf $(BUILDDIR)/*
53+
54+.PHONY: html
55+html:
56+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
57+ @echo
58+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
59+
60+.PHONY: dirhtml
61+dirhtml:
62+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
63+ @echo
64+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
65+
66+.PHONY: singlehtml
67+singlehtml:
68+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
69+ @echo
70+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
71+
72+.PHONY: pickle
73+pickle:
74+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
75+ @echo
76+ @echo "Build finished; now you can process the pickle files."
77+
78+.PHONY: json
79+json:
80+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
81+ @echo
82+ @echo "Build finished; now you can process the JSON files."
83+
84+.PHONY: htmlhelp
85+htmlhelp:
86+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
87+ @echo
88+ @echo "Build finished; now you can run HTML Help Workshop with the" \
89+ ".hhp project file in $(BUILDDIR)/htmlhelp."
90+
91+.PHONY: qthelp
92+qthelp:
93+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
94+ @echo
95+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
96+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
97+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/generics-eot.qhcp"
98+ @echo "To view the help file:"
99+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/generics-eot.qhc"
100+
101+.PHONY: applehelp
102+applehelp:
103+ $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
104+ @echo
105+ @echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
106+ @echo "N.B. You won't be able to view it unless you put it in" \
107+ "~/Library/Documentation/Help or install it in your application" \
108+ "bundle."
109+
110+.PHONY: devhelp
111+devhelp:
112+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
113+ @echo
114+ @echo "Build finished."
115+ @echo "To view the help file:"
116+ @echo "# mkdir -p $$HOME/.local/share/devhelp/generics-eot"
117+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/generics-eot"
118+ @echo "# devhelp"
119+
120+.PHONY: epub
121+epub:
122+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
123+ @echo
124+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
125+
126+.PHONY: latex
127+latex:
128+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
129+ @echo
130+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
131+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
132+ "(use \`make latexpdf' here to do that automatically)."
133+
134+.PHONY: latexpdf
135+latexpdf:
136+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
137+ @echo "Running LaTeX files through pdflatex..."
138+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
139+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
140+
141+.PHONY: latexpdfja
142+latexpdfja:
143+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
144+ @echo "Running LaTeX files through platex and dvipdfmx..."
145+ $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
146+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
147+
148+.PHONY: text
149+text:
150+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
151+ @echo
152+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
153+
154+.PHONY: man
155+man:
156+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
157+ @echo
158+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
159+
160+.PHONY: texinfo
161+texinfo:
162+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
163+ @echo
164+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
165+ @echo "Run \`make' in that directory to run these through makeinfo" \
166+ "(use \`make info' here to do that automatically)."
167+
168+.PHONY: info
169+info:
170+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
171+ @echo "Running Texinfo files through makeinfo..."
172+ make -C $(BUILDDIR)/texinfo info
173+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
174+
175+.PHONY: gettext
176+gettext:
177+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
178+ @echo
179+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
180+
181+.PHONY: changes
182+changes:
183+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
184+ @echo
185+ @echo "The overview file is in $(BUILDDIR)/changes."
186+
187+.PHONY: linkcheck
188+linkcheck:
189+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
190+ @echo
191+ @echo "Link check complete; look for any errors in the above output " \
192+ "or in $(BUILDDIR)/linkcheck/output.txt."
193+
194+.PHONY: doctest
195+doctest:
196+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
197+ @echo "Testing of doctests in the sources finished, look at the " \
198+ "results in $(BUILDDIR)/doctest/output.txt."
199+
200+.PHONY: coverage
201+coverage:
202+ $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
203+ @echo "Testing of coverage in the sources finished, look at the " \
204+ "results in $(BUILDDIR)/coverage/python.txt."
205+
206+.PHONY: xml
207+xml:
208+ $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
209+ @echo
210+ @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
211+
212+.PHONY: pseudoxml
213+pseudoxml:
214+ $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
215+ @echo
216+ @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
tutorial/api-type.lhsnew file+309
@@ -0,0 +1,309 @@
1+---
2+title: A web API as a type
3+toc: true
4+---
5+
6+The source for this tutorial section is a literate haskell file, so first we
7+need to have some language extensions and imports:
8+
9+> {-# LANGUAGE DataKinds #-}
10+> {-# LANGUAGE TypeOperators #-}
11+>
12+> module ApiType where
13+>
14+> import Data.Text
15+> import Servant.API
16+
17+Consider the following informal specification of an API:
18+
19+ > The endpoint at `/users` expects a GET request with query string parameter
20+ > `sortby` whose value can be one of `age` or `name` and returns a
21+ > list/array of JSON objects describing users, with fields `age`, `name`,
22+ > `email`, `registration_date`".
23+
24+You *should* be able to formalize that. And then use the formalized version to
25+get you much of the way towards writing a web app. And all the way towards
26+getting some client libraries, and documentation (and in the future, who knows
27+- tests, HATEOAS, ...).
28+
29+How would we describe it with servant? As mentioned earlier, an endpoint
30+description is a good old Haskell **type**:
31+
32+> type UserAPI = "users" :> QueryParam "sortby" SortBy :> Get '[JSON] [User]
33+>
34+> data SortBy = Age | Name
35+>
36+> data User = User {
37+> name :: String,
38+> age :: Int
39+> }
40+
41+Let's break that down:
42+
43+- `"users"` says that our endpoint will be accessible under `/users`;
44+- `QueryParam "sortby" SortBy`, where `SortBy` is defined by `data SortBy = Age
45+| Name`, says that the endpoint has a query string parameter named `sortby`
46+whose value will be extracted as a value of type `SortBy`.
47+- `Get '[JSON] [User]` says that the endpoint will be accessible through HTTP
48+GET requests, returning a list of users encoded as JSON. You will see
49+later how you can make use of this to make your data available under different
50+formats, the choice being made depending on the [Accept
51+header](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html) specified in
52+the client's request.
53+- the `:>` operator that separates the various "combinators" just lets you
54+sequence static path fragments, URL captures and other combinators. The
55+ordering only matters for static path fragments and URL captures. `"users" :>
56+"list-all" :> Get '[JSON] [User]`, equivalent to `/users/list-all`, is
57+obviously not the same as `"list-all" :> "users" :> Get '[JSON] [User]`, which
58+is equivalent to `/list-all/users`. This means that sometimes `:>` is somehow
59+equivalent to `/`, but sometimes it just lets you chain another combinator.
60+
61+We can also describe APIs with multiple endpoints by using the `:<|>`
62+combinators. Here's an example:
63+
64+> type UserAPI2 = "users" :> "list-all" :> Get '[JSON] [User]
65+> :<|> "list-all" :> "users" :> Get '[JSON] [User]
66+
67+*servant* provides a fair amount of combinators out-of-the-box, but you can
68+always write your own when you need it. Here's a quick overview of all the
69+combinators that servant comes with.
70+
71+Combinators
72+===========
73+
74+Static strings
75+--------------
76+
77+As you've already seen, you can use type-level strings (enabled with the
78+`DataKinds` language extension) for static path fragments. Chaining
79+them amounts to `/`-separating them in a URL.
80+
81+> type UserAPI3 = "users" :> "list-all" :> "now" :> Get '[JSON] [User]
82+> -- describes an endpoint reachable at:
83+> -- /users/list-all/now
84+
85+`Delete`, `Get`, `Patch`, `Post` and `Put`
86+------------------------------------------
87+
88+These 5 combinators are very similar except that they each describe a
89+different HTTP method. This is how they're declared
90+
91+``` haskell
92+data Delete (contentTypes :: [*]) a
93+data Get (contentTypes :: [*]) a
94+data Patch (contentTypes :: [*]) a
95+data Post (contentTypes :: [*]) a
96+data Put (contentTypes :: [*]) a
97+```
98+
99+An endpoint ends with one of the 5 combinators above (unless you write your
100+own). Examples:
101+
102+> type UserAPI4 = "users" :> Get '[JSON] [User]
103+> :<|> "admins" :> Get '[JSON] [User]
104+
105+`Capture`
106+---------
107+
108+URL captures are parts of the URL that are variable and whose actual value is
109+captured and passed to the request handlers. In many web frameworks, you'll see
110+it written as in `/users/:userid`, with that leading `:` denoting that `userid`
111+is just some kind of variable name or placeholder. For instance, if `userid` is
112+supposed to range over all integers greater or equal to 1, our endpoint will
113+match requests made to `/users/1`, `/users/143` and so on.
114+
115+The `Capture` combinator in servant takes a (type-level) string representing
116+the "name of the variable" and a type, which indicates the type we want to
117+decode the "captured value" to.
118+
119+``` haskell
120+data Capture (s :: Symbol) a
121+-- s :: Symbol just says that 's' must be a type-level string.
122+```
123+
124+In some web frameworks, you use regexes for captures. We use a
125+[`FromText`](https://hackage.haskell.org/package/servant/docs/Servant-Common-Text.html#t:FromText)
126+class, which the captured value must be an instance of.
127+
128+Examples:
129+
130+> type UserAPI5 = "user" :> Capture "userid" Integer :> Get '[JSON] User
131+> -- equivalent to 'GET /user/:userid'
132+> -- except that we explicitly say that "userid"
133+> -- must be an integer
134+>
135+> :<|> "user" :> Capture "userid" Integer :> Delete '[] ()
136+> -- equivalent to 'DELETE /user/:userid'
137+
138+`QueryParam`, `QueryParams`, `QueryFlag`, `MatrixParam`, `MatrixParams` and `MatrixFlag`
139+----------------------------------------------------------------------------------------
140+
141+`QueryParam`, `QueryParams` and `QueryFlag` are about query string
142+parameters, i.e., those parameters that come after the question mark
143+(`?`) in URLs, like `sortby` in `/users?sortby=age`, whose value is
144+set to `age`. `QueryParams` lets you specify that the query parameter
145+is actually a list of values, which can be specified using
146+`?param[]=value1&param[]=value2`. This represents a list of values
147+composed of `value1` and `value2`. `QueryFlag` lets you specify a
148+boolean-like query parameter where a client isn't forced to specify a
149+value. The absence or presence of the parameter's name in the query
150+string determines whether the parameter is considered to have the
151+value `True` or `False`. For instance, `/users?active` would list only
152+active users whereas `/users` would list them all.
153+
154+Here are the corresponding data type declarations:
155+
156+``` haskell
157+data QueryParam (sym :: Symbol) a
158+data QueryParams (sym :: Symbol) a
159+data QueryFlag (sym :: Symbol)
160+```
161+
162+[Matrix parameters](http://www.w3.org/DesignIssues/MatrixURIs.html)
163+are similar to query string parameters, but they can appear anywhere
164+in the paths (click the link for more details). A URL with matrix
165+parameters in it looks like `/users;sortby=age`, as opposed to
166+`/users?sortby=age` with query string parameters. The big advantage is
167+that they are not necessarily at the end of the URL. You could have
168+`/users;active=true;registered_after=2005-01-01/locations` to get
169+geolocation data about users whom are still active and registered
170+after *January 1st, 2005*.
171+
172+Corresponding data type declarations below.
173+
174+``` haskell
175+data MatrixParam (sym :: Symbol) a
176+data MatrixParams (sym :: Symbol) a
177+data MatrixFlag (sym :: Symbol)
178+```
179+
180+Examples:
181+
182+> type UserAPI6 = "users" :> QueryParam "sortby" SortBy :> Get '[JSON] [User]
183+> -- equivalent to 'GET /users?sortby={age, name}'
184+>
185+> :<|> "users" :> MatrixParam "sortby" SortBy :> Get '[JSON] [User]
186+> -- equivalent to 'GET /users;sortby={age, name}'
187+
188+Again, your handlers don't have to deserialize these things (into, for example,
189+a `SortBy`). *servant* takes care of it.
190+
191+`ReqBody`
192+---------
193+
194+Each HTTP request can carry some additional data that the server can use in its
195+*body*, and this data can be encoded in any format -- as long as the server
196+understands it. This can be used for example for an endpoint for creating new
197+users: instead of passing each field of the user as a separate query string
198+parameter or something dirty like that, we can group all the data into a JSON
199+object. This has the advantage of supporting nested objects.
200+
201+*servant*'s `ReqBody` combinator takes a list of content types in which the
202+data encoded in the request body can be represented and the type of that data.
203+And, as you might have guessed, you don't have to check the content-type
204+header, and do the deserialization yourself. We do it for you. And return `Bad
205+Request` or `Unsupported Content Type` as appropriate.
206+
207+Here's the data type declaration for it:
208+
209+``` haskell
210+data ReqBody (contentTypes :: [*]) a
211+```
212+
213+Examples:
214+
215+> type UserAPI7 = "users" :> ReqBody '[JSON] User :> Post '[JSON] User
216+> -- - equivalent to 'POST /users' with a JSON object
217+> -- describing a User in the request body
218+> -- - returns a User encoded in JSON
219+>
220+> :<|> "users" :> Capture "userid" Integer
221+> :> ReqBody '[JSON] User
222+> :> Put '[JSON] User
223+> -- - equivalent to 'PUT /users/:userid' with a JSON
224+> -- object describing a User in the request body
225+> -- - returns a User encoded in JSON
226+
227+Request `Header`s
228+-----------------
229+
230+Request headers are used for various purposes, from caching to carrying
231+auth-related data. They consist of a header name and an associated value. An
232+example would be `Accept: application/json`.
233+
234+The `Header` combinator in servant takes a type-level string for the header
235+name and the type to which we want to decode the header's value (from some
236+textual representation), as illustrated below:
237+
238+``` haskell
239+data Header (sym :: Symbol) a
240+```
241+
242+Here's an example where we declare that an endpoint makes use of the
243+`User-Agent` header which specifies the name of the software/library used by
244+the client to send the request.
245+
246+> type UserAPI8 = "users" :> Header "User-Agent" Text :> Get '[JSON] [User]
247+
248+Content types
249+-------------
250+
251+So far, whenever we have used a combinator that carries a list of content
252+types, we've always specified `'[JSON]`. However, *servant* lets you use several
253+content types, and also lets you define your own content types.
254+
255+Four content-types are provided out-of-the-box by the core *servant* package:
256+`JSON`, `PlainText`, `FormUrlEncoded` and `OctetStream`. If for some obscure
257+reason you wanted one of your endpoints to make your user data available under
258+those 4 formats, you would write the API type as below:
259+
260+> type UserAPI9 = "users" :> Get '[JSON, PlainText, FormUrlEncoded, OctetStream] [User]
261+
262+We also provide an HTML content-type, but since there's no single library
263+that everyone uses, we decided to release 2 packages, *servant-lucid* and
264+*servant-blaze*, to provide HTML encoding of your data.
265+
266+We will further explain how these content types and your data types can play
267+together in the [section about serving an API](/tutorial/server.html).
268+
269+Response `Headers`
270+------------------
271+
272+Just like an HTTP request, the response generated by a webserver can carry
273+headers too. *servant* provides a `Headers` combinator that carries a list of
274+`Header` and can be used by simply wrapping the "return type" of an endpoint
275+with it.
276+
277+``` haskell
278+data Headers (ls :: [*]) a
279+```
280+
281+If you want to describe an endpoint that returns a "User-Count" header in each
282+response, you could write it as below:
283+
284+> type UserAPI10 = "users" :> Get '[JSON] (Headers '[Header "User-Count" Integer] [User])
285+
286+Interoperability with other WAI `Application`s: `Raw`
287+-----------------------------------------------------
288+
289+Finally, we also include a combinator named `Raw` that can be used for two reasons:
290+
291+- You want to serve static files from a given directory. In that case you can just say:
292+
293+> type UserAPI11 = "users" :> Get '[JSON] [User]
294+> -- a /users endpoint
295+>
296+> :<|> Raw
297+> -- requests to anything else than /users
298+> -- go here, where the server will try to
299+> -- find a file with the right name
300+> -- at the right path
301+
302+- You more generally want to plug a [WAI `Application`](http://hackage.haskell.org/package/wai)
303+into your webservice. Static file serving is a specific example of that. The API type would look the
304+same as above though. (You can even combine *servant* with other web frameworks
305+this way!)
306+
307+<div style="text-align: center;">
308+ <a href="/tutorial/server.html">Next page: Serving an API</a>
309+</div>
tutorial/client.lhsnew file+138
@@ -0,0 +1,138 @@
1+---
2+title: Deriving Haskell functions to query an API
3+toc: true
4+---
5+
6+While defining handlers that serve an API has a lot to it, querying an API is simpler: we do not care about what happens inside the webserver, we just need to know how to talk to it and get a response back. Except that we usually have to write the querying functions by hand because the structure of the API isn't a first class citizen and can't be inspected to generate a bunch of client-side functions.
7+
8+*servant* however has a way to inspect API, because APIs are just Haskell types and (GHC) Haskell lets us do quite a few things with types. In the same way that we look at an API type to deduce the types the handlers should have, we can inspect the structure of the API to *derive* Haskell functions that take one argument for each occurence of `Capture`, `ReqBody`, `QueryParam`
9+and friends. By *derive*, we mean that there's no code generation involved, the functions are defined just by the structure of the API type.
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+> {-# LANGUAGE DataKinds #-}
15+> {-# LANGUAGE DeriveGeneric #-}
16+> {-# LANGUAGE TypeOperators #-}
17+>
18+> module Client where
19+>
20+> import Control.Monad.Trans.Either
21+> import Data.Aeson
22+> import Data.Proxy
23+> import GHC.Generics
24+> import Servant.API
25+> import Servant.Client
26+
27+Also, we need examples for some domain specific data types:
28+
29+> data Position = Position
30+> { x :: Int
31+> , y :: Int
32+> } deriving (Show, Generic)
33+>
34+> instance FromJSON Position
35+>
36+> newtype HelloMessage = HelloMessage { msg :: String }
37+> deriving (Show, Generic)
38+>
39+> instance FromJSON HelloMessage
40+>
41+> data ClientInfo = ClientInfo
42+> { clientName :: String
43+> , clientEmail :: String
44+> , clientAge :: Int
45+> , clientInterestedIn :: [String]
46+> } deriving Generic
47+>
48+> instance ToJSON ClientInfo
49+>
50+> data Email = Email
51+> { from :: String
52+> , to :: String
53+> , subject :: String
54+> , body :: String
55+> } deriving (Show, Generic)
56+>
57+> instance FromJSON Email
58+
59+Enough chitchat, let's see an example. Consider the following API type from the previous section:
60+
61+> type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
62+> :<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
63+> :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email
64+
65+What we are going to get with *servant-client* here is 3 functions, one to query each endpoint:
66+
67+> position :: Int -- ^ value for "x"
68+> -> Int -- ^ value for "y"
69+> -> EitherT ServantError IO Position
70+>
71+> hello :: Maybe String -- ^ an optional value for "name"
72+> -> EitherT ServantError IO HelloMessage
73+>
74+> marketing :: ClientInfo -- ^ value for the request body
75+> -> EitherT ServantError IO Email
76+
77+Each function makes available as an argument any value that the response may depend on, as evidenced in the API type. How do we get these functions? Just give a `Proxy` to your API and a host to make the requests to:
78+
79+> api :: Proxy API
80+> api = Proxy
81+>
82+> position :<|> hello :<|> marketing = client api (BaseUrl Http "localhost" 8081)
83+
84+As you can see in the code above, we just "pattern match our way" to these functions. If we try to derive less or more functions than there are endpoints in the API, we obviously get an error. The `BaseUrl` value there is just:
85+
86+``` haskell
87+-- | URI scheme to use
88+data Scheme =
89+ Http -- ^ http://
90+ | Https -- ^ https://
91+ deriving
92+
93+-- | Simple data type to represent the target of HTTP requests
94+-- for servant's automatically-generated clients.
95+data BaseUrl = BaseUrl
96+ { baseUrlScheme :: Scheme -- ^ URI scheme to use
97+ , baseUrlHost :: String -- ^ host (eg "haskell.org")
98+ , baseUrlPort :: Int -- ^ port (eg 80)
99+ }
100+```
101+
102+That's it. Let's now write some code that uses our client functions.
103+
104+> queries :: EitherT ServantError IO (Position, HelloMessage, Email)
105+> queries = do
106+> pos <- position 10 10
107+> msg <- hello (Just "servant")
108+> em <- marketing (ClientInfo "Alp" "alp@foo.com" 26 ["haskell", "mathematics"])
109+> return (pos, msg, em)
110+>
111+> run :: IO ()
112+> run = do
113+> res <- runEitherT queries
114+> case res of
115+> Left err -> putStrLn $ "Error: " ++ show err
116+> Right (pos, msg, em) -> do
117+> print pos
118+> print msg
119+> print em
120+
121+You can now run `dist/build/tutorial/tutorial 8` (the server) and
122+`dist/build/t8-main/t8-main` (the client) to see them both in action.
123+
124+``` bash
125+ $ dist/build/tutorial/tutorial 8
126+ # and in another terminal:
127+ $ dist/build/t8-main/t8-main
128+ Position {x = 10, y = 10}
129+ HelloMessage {msg = "Hello, servant"}
130+ Email {from = "great@company.com", to = "alp@foo.com", subject = "Hey Alp, we miss you!", body = "Hi Alp,\n\nSince you've recently turned 26, have you checked out our latest haskell, mathematics products? Give us a visit!"}
131+```
132+
133+The types of the arguments for the functions are the same as for (server-side) request handlers. You now know how to use *servant-client*!
134+
135+<div style="text-align: center;">
136+ <p><a href="/tutorial/server.html">Previous page: Serving an API</a></p>
137+ <p><a href="/tutorial/javascript.html">Next page: Generating javascript functions to query an API</a></p>
138+</div>
tutorial/conf.pynew file+287
@@ -0,0 +1,287 @@
1+# -*- coding: utf-8 -*-
2+#
3+# generics-eot documentation build configuration file, created by
4+# sphinx-quickstart on Fri Jan 22 12:22:48 2016.
5+#
6+# This file is execfile()d with the current directory set to its
7+# containing dir.
8+#
9+# Note that not all possible configuration values are present in this
10+# autogenerated file.
11+#
12+# All configuration values have a default; values that are commented out
13+# serve to show the default.
14+
15+import sys
16+import os
17+from recommonmark.parser import CommonMarkParser
18+
19+# If extensions (or modules to document with autodoc) are in another directory,
20+# add these directories to sys.path here. If the directory is relative to the
21+# documentation root, use os.path.abspath to make it absolute, like shown here.
22+#sys.path.insert(0, os.path.abspath('.'))
23+
24+# -- General configuration ------------------------------------------------
25+
26+# If your documentation needs a minimal Sphinx version, state it here.
27+#needs_sphinx = '1.0'
28+
29+# Add any Sphinx extension module names here, as strings. They can be
30+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
31+# ones.
32+extensions = []
33+
34+# Add any paths that contain templates here, relative to this directory.
35+templates_path = ['_templates']
36+
37+# The suffix(es) of source filenames.
38+# You can specify multiple suffix as a list of string:
39+source_suffix = ['.md', '.rst']
40+
41+# The encoding of source files.
42+#source_encoding = 'utf-8-sig'
43+
44+# The master toctree document.
45+master_doc = 'index'
46+
47+# General information about the project.
48+project = u'generics-eot'
49+copyright = u'2016, Sönke Hahn'
50+author = u'Sönke Hahn'
51+
52+# The version info for the project you're documenting, acts as replacement for
53+# |version| and |release|, also used in various other places throughout the
54+# built documents.
55+#
56+# The short X.Y version.
57+version = u'0.1'
58+# The full version, including alpha/beta/rc tags.
59+release = u'0.1'
60+
61+# The language for content autogenerated by Sphinx. Refer to documentation
62+# for a list of supported languages.
63+#
64+# This is also used if you do content translation via gettext catalogs.
65+# Usually you set "language" from the command line for these cases.
66+language = None
67+
68+# There are two options for replacing |today|: either, you set today to some
69+# non-false value, then it is used:
70+#today = ''
71+# Else, today_fmt is used as the format for a strftime call.
72+#today_fmt = '%B %d, %Y'
73+
74+# List of patterns, relative to source directory, that match files and
75+# directories to ignore when looking for source files.
76+exclude_patterns = ['_build', 'venv']
77+
78+# The reST default role (used for this markup: `text`) to use for all
79+# documents.
80+#default_role = None
81+
82+# If true, '()' will be appended to :func: etc. cross-reference text.
83+#add_function_parentheses = True
84+
85+# If true, the current module name will be prepended to all description
86+# unit titles (such as .. function::).
87+#add_module_names = True
88+
89+# If true, sectionauthor and moduleauthor directives will be shown in the
90+# output. They are ignored by default.
91+#show_authors = False
92+
93+# The name of the Pygments (syntax highlighting) style to use.
94+pygments_style = 'sphinx'
95+
96+# A list of ignored prefixes for module index sorting.
97+#modindex_common_prefix = []
98+
99+# If true, keep warnings as "system message" paragraphs in the built documents.
100+#keep_warnings = False
101+
102+# If true, `todo` and `todoList` produce output, else they produce nothing.
103+todo_include_todos = False
104+
105+
106+# -- Options for HTML output ----------------------------------------------
107+
108+# The theme to use for HTML and HTML Help pages. See the documentation for
109+# a list of builtin themes.
110+html_theme = 'alabaster'
111+
112+# Theme options are theme-specific and customize the look and feel of a theme
113+# further. For a list of options available for each theme, see the
114+# documentation.
115+#html_theme_options = {}
116+
117+# Add any paths that contain custom themes here, relative to this directory.
118+#html_theme_path = []
119+
120+# The name for this set of Sphinx documents. If None, it defaults to
121+# "<project> v<release> documentation".
122+#html_title = None
123+
124+# A shorter title for the navigation bar. Default is the same as html_title.
125+#html_short_title = None
126+
127+# The name of an image file (relative to this directory) to place at the top
128+# of the sidebar.
129+#html_logo = None
130+
131+# The name of an image file (within the static path) to use as favicon of the
132+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
133+# pixels large.
134+#html_favicon = None
135+
136+# Add any paths that contain custom static files (such as style sheets) here,
137+# relative to this directory. They are copied after the builtin static files,
138+# so a file named "default.css" will overwrite the builtin "default.css".
139+html_static_path = ['_static']
140+
141+# Add any extra paths that contain custom files (such as robots.txt or
142+# .htaccess) here, relative to this directory. These files are copied
143+# directly to the root of the documentation.
144+#html_extra_path = []
145+
146+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
147+# using the given strftime format.
148+#html_last_updated_fmt = '%b %d, %Y'
149+
150+# If true, SmartyPants will be used to convert quotes and dashes to
151+# typographically correct entities.
152+#html_use_smartypants = True
153+
154+# Custom sidebar templates, maps document names to template names.
155+#html_sidebars = {}
156+
157+# Additional templates that should be rendered to pages, maps page names to
158+# template names.
159+#html_additional_pages = {}
160+
161+# If false, no module index is generated.
162+#html_domain_indices = True
163+
164+# If false, no index is generated.
165+#html_use_index = True
166+
167+# If true, the index is split into individual pages for each letter.
168+#html_split_index = False
169+
170+# If true, links to the reST sources are added to the pages.
171+#html_show_sourcelink = True
172+
173+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
174+#html_show_sphinx = True
175+
176+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
177+#html_show_copyright = True
178+
179+# If true, an OpenSearch description file will be output, and all pages will
180+# contain a <link> tag referring to it. The value of this option must be the
181+# base URL from which the finished HTML is served.
182+#html_use_opensearch = ''
183+
184+# This is the file name suffix for HTML files (e.g. ".xhtml").
185+#html_file_suffix = None
186+
187+# Language to be used for generating the HTML full-text search index.
188+# Sphinx supports the following languages:
189+# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
190+# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
191+#html_search_language = 'en'
192+
193+# A dictionary with options for the search language support, empty by default.
194+# Now only 'ja' uses this config value
195+#html_search_options = {'type': 'default'}
196+
197+# The name of a javascript file (relative to the configuration directory) that
198+# implements a search results scorer. If empty, the default will be used.
199+#html_search_scorer = 'scorer.js'
200+
201+# Output file base name for HTML help builder.
202+htmlhelp_basename = 'generics-eotdoc'
203+
204+# -- Options for LaTeX output ---------------------------------------------
205+
206+latex_elements = {
207+# The paper size ('letterpaper' or 'a4paper').
208+#'papersize': 'letterpaper',
209+
210+# The font size ('10pt', '11pt' or '12pt').
211+#'pointsize': '10pt',
212+
213+# Additional stuff for the LaTeX preamble.
214+#'preamble': '',
215+
216+# Latex figure (float) alignment
217+#'figure_align': 'htbp',
218+}
219+
220+# Grouping the document tree into LaTeX files. List of tuples
221+# (source start file, target name, title,
222+# author, documentclass [howto, manual, or own class]).
223+latex_documents = [
224+ (master_doc, 'generics-eot.tex', u'generics-eot Documentation',
225+ u'Sönke Hahn', 'manual'),
226+]
227+
228+# The name of an image file (relative to this directory) to place at the top of
229+# the title page.
230+#latex_logo = None
231+
232+# For "manual" documents, if this is true, then toplevel headings are parts,
233+# not chapters.
234+#latex_use_parts = False
235+
236+# If true, show page references after internal links.
237+#latex_show_pagerefs = False
238+
239+# If true, show URL addresses after external links.
240+#latex_show_urls = False
241+
242+# Documents to append as an appendix to all manuals.
243+#latex_appendices = []
244+
245+# If false, no module index is generated.
246+#latex_domain_indices = True
247+
248+
249+# -- Options for manual page output ---------------------------------------
250+
251+# One entry per manual page. List of tuples
252+# (source start file, name, description, authors, manual section).
253+man_pages = [
254+ (master_doc, 'generics-eot', u'generics-eot Documentation',
255+ [author], 1)
256+]
257+
258+# If true, show URL addresses after external links.
259+#man_show_urls = False
260+
261+
262+# -- Options for Texinfo output -------------------------------------------
263+
264+# Grouping the document tree into Texinfo files. List of tuples
265+# (source start file, target name, title, author,
266+# dir menu entry, description, category)
267+texinfo_documents = [
268+ (master_doc, 'generics-eot', u'generics-eot Documentation',
269+ author, 'generics-eot', 'One line description of project.',
270+ 'Miscellaneous'),
271+]
272+
273+# Documents to append as an appendix to all manuals.
274+#texinfo_appendices = []
275+
276+# If false, no module index is generated.
277+#texinfo_domain_indices = True
278+
279+# How to display URL addresses: 'footnote', 'no', or 'inline'.
280+#texinfo_show_urls = 'footnote'
281+
282+# If true, do not generate a @detailmenu in the "Top" node's menu.
283+#texinfo_no_detailmenu = False
284+
285+source_parsers = {
286+ '.md': CommonMarkParser,
287+}
tutorial/docs.lhsnew file+227
@@ -0,0 +1,227 @@
1+---
2+title: Generating documentation from API types
3+toc: true
4+---
5+
6+The source for this tutorial section is a literate haskell file, so first we
7+need to have some language extensions and imports:
8+
9+> {-# LANGUAGE DataKinds #-}
10+> {-# LANGUAGE DeriveGeneric #-}
11+> {-# LANGUAGE FlexibleInstances #-}
12+> {-# LANGUAGE MultiParamTypeClasses #-}
13+> {-# LANGUAGE OverloadedStrings #-}
14+> {-# LANGUAGE TypeOperators #-}
15+> {-# OPTIONS_GHC -fno-warn-orphans #-}
16+>
17+> module Docs where
18+>
19+> import Data.ByteString.Lazy (ByteString)
20+> import Data.Proxy
21+> import Data.Text.Lazy.Encoding (encodeUtf8)
22+> import Data.Text.Lazy (pack)
23+> import Network.HTTP.Types
24+> import Network.Wai
25+> import Servant.API
26+> import Servant.Docs
27+> import Servant.Server
28+
29+And we'll import some things from one of our earlier modules
30+([Serving an API](/tutorial/server.html)):
31+
32+> import Server (Email(..), ClientInfo(..), Position(..), HelloMessage(..),
33+> server3, emailForClient)
34+
35+Like client function generation, documentation generation amounts to inspecting the API type and extracting all the data we need to then present it in some format to users of your API.
36+
37+This time however, we have to assist *servant*. While it is able to deduce a lot of things about our API, it can't magically come up with descriptions of the various pieces of our APIs that are human-friendly and explain what's going on "at the business-logic level". A good example to study for documentation generation is our webservice with the `/position`, `/hello` and `/marketing` endpoints from earlier:
38+
39+> type ExampleAPI = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
40+> :<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
41+> :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email
42+>
43+> exampleAPI :: Proxy ExampleAPI
44+> exampleAPI = Proxy
45+
46+While *servant* can see e.g. that there are 3 endpoints and that the response bodies will be in JSON, it doesn't know what influence the captures, parameters, request bodies and other combinators have on the webservice. This is where some manual work is required.
47+
48+For every capture, request body, response body, query param, we have to give some explanations about how it influences the response, what values are possible and the likes. Here's how it looks like for the parameters we have above.
49+
50+> instance ToCapture (Capture "x" Int) where
51+> toCapture _ =
52+> DocCapture "x" -- name
53+> "(integer) position on the x axis" -- description
54+>
55+> instance ToCapture (Capture "y" Int) where
56+> toCapture _ =
57+> DocCapture "y" -- name
58+> "(integer) position on the y axis" -- description
59+>
60+> instance ToSample Position Position where
61+> toSample _ = Just (Position 3 14) -- example of output
62+>
63+> instance ToParam (QueryParam "name" String) where
64+> toParam _ =
65+> DocQueryParam "name" -- name
66+> ["Alp", "John Doe", "..."] -- example of values (not necessarily exhaustive)
67+> "Name of the person to say hello to." -- description
68+> Normal -- Normal, List or Flag
69+>
70+> instance ToSample HelloMessage HelloMessage where
71+> toSamples _ =
72+> [ ("When a value is provided for 'name'", HelloMessage "Hello, Alp")
73+> , ("When 'name' is not specified", HelloMessage "Hello, anonymous coward")
74+> ]
75+> -- mutliple examples to display this time
76+>
77+> ci :: ClientInfo
78+> ci = ClientInfo "Alp" "alp@foo.com" 26 ["haskell", "mathematics"]
79+>
80+> instance ToSample ClientInfo ClientInfo where
81+> toSample _ = Just ci
82+>
83+> instance ToSample Email Email where
84+> toSample _ = Just (emailForClient ci)
85+
86+Types that are used as request or response bodies have to instantiate the `ToSample` typeclass which lets you specify one or more examples of values. `Capture`s and `QueryParam`s have to instantiate their respective `ToCapture` and `ToParam` classes and provide a name and some information about the concrete meaning of that argument, as illustrated in the code above.
87+
88+With all of this, we can derive docs for our API.
89+
90+> apiDocs :: API
91+> apiDocs = docs exampleAPI
92+
93+`API` is a type provided by *servant-docs* that stores all the information one needs about a web API in order to generate documentation in some format. Out of the box, *servant-docs* only provides a pretty documentation printer that outputs [Markdown](http://en.wikipedia.org/wiki/Markdown), but the [servant-pandoc](http://hackage.haskell.org/package/servant-pandoc) package can be used to target many useful formats.
94+
95+*servant*'s markdown pretty printer is a function named `markdown`.
96+
97+``` haskell
98+markdown :: API -> String
99+```
100+
101+That lets us see what our API docs look down in markdown, by looking at `markdown apiDocs`.
102+
103+``` text
104+ ## Welcome
105+
106+ This is our super webservice's API.
107+
108+ Enjoy!
109+
110+ ## GET /hello
111+
112+ #### GET Parameters:
113+
114+ - name
115+ - **Values**: *Alp, John Doe, ...*
116+ - **Description**: Name of the person to say hello to.
117+
118+
119+ #### Response:
120+
121+ - Status code 200
122+ - Headers: []
123+
124+ - Supported content types are:
125+
126+ - `application/json`
127+
128+ - When a value is provided for 'name'
129+
130+ ```javascript
131+ {"msg":"Hello, Alp"}
132+ ```
133+
134+ - When 'name' is not specified
135+
136+ ```javascript
137+ {"msg":"Hello, anonymous coward"}
138+ ```
139+
140+ ## POST /marketing
141+
142+ #### Request:
143+
144+ - Supported content types are:
145+
146+ - `application/json`
147+
148+ - Example: `application/json`
149+
150+ ```javascript
151+ {"email":"alp@foo.com","interested_in":["haskell","mathematics"],"age":26,"name":"Alp"}
152+ ```
153+
154+ #### Response:
155+
156+ - Status code 201
157+ - Headers: []
158+
159+ - Supported content types are:
160+
161+ - `application/json`
162+
163+ - Response body as below.
164+
165+ ```javascript
166+ {"subject":"Hey Alp, we miss you!","body":"Hi Alp,\n\nSince you've recently turned 26, have you checked out our latest haskell, mathematics products? Give us a visit!","to":"alp@foo.com","from":"great@company.com"}
167+ ```
168+
169+ ## GET /position/:x/:y
170+
171+ #### Captures:
172+
173+ - *x*: (integer) position on the x axis
174+ - *y*: (integer) position on the y axis
175+
176+ #### Response:
177+
178+ - Status code 200
179+ - Headers: []
180+
181+ - Supported content types are:
182+
183+ - `application/json`
184+
185+ - Response body as below.
186+
187+ ```javascript
188+ {"x":3,"y":14}
189+ ```
190+
191+```
192+
193+However, we can also add one or more introduction sections to the document. We just need to tweak the way we generate `apiDocs`. We will also convert the content to a lazy `ByteString` since this is what *wai* expects for `Raw` endpoints.
194+
195+> docsBS :: ByteString
196+> docsBS = encodeUtf8
197+> . pack
198+> . markdown
199+> $ docsWithIntros [intro] exampleAPI
200+>
201+> where intro = DocIntro "Welcome" ["This is our super webservice's API.", "Enjoy!"]
202+
203+`docsWithIntros` just takes an additional parameter, a list of `DocIntro`s that must be displayed before any endpoint docs.
204+
205+We can now serve the API *and* the API docs with a simple server.
206+
207+> type DocsAPI = ExampleAPI :<|> Raw
208+>
209+> api :: Proxy DocsAPI
210+> api = Proxy
211+>
212+> server :: Server DocsAPI
213+> server = Server.server3 :<|> serveDocs
214+>
215+> where serveDocs _ respond =
216+> respond $ responseLBS ok200 [plain] docsBS
217+>
218+> plain = ("Content-Type", "text/plain")
219+>
220+> app :: Application
221+> app = serve api server
222+
223+And if you spin up this server with `dist/build/tutorial/tutorial 10` and go to anywhere else than `/position`, `/hello` and `/marketing`, you will see the API docs in markdown. This is because `serveDocs` is attempted if the 3 other endpoints don't match and systematically succeeds since its definition is to just return some fixed bytestring with the `text/plain` content type.
224+
225+<div style="text-align: center;">
226+ <a href="/tutorial/javascript.html">Previous page: Generating javascript functions to query an API</a>
227+</div>
tutorial/index.rstnew file+68
@@ -0,0 +1,68 @@
1+Servant tutorial
2+================
3+
4+This is an introductory tutorial to the current version of *servant*, which is **0.4**. Any comment or issue can be directed to [this website's issue tracker](http://github.com/haskell-servant/haskell-servant.github.io/issues).
5+
6+Github
7+-------
8+
9+- the servant packages: [haskell-servant/servant](https://github.com/haskell-servant/servant)
10+- the website (including this tutorial): [haskell-servant/haskell-servant.github.io](https://github.com/haskell-servant/haskell-servant.github.io/)
11+- Feel free to use the issue tracker (or to send PRs!) on the website's repository to give feedback and suggestions about this tutorial
12+
13+Introduction
14+-------------
15+
16+*servant* has the following guiding principles:
17+
18+- concision
19+
20+ This is a pretty wide-ranging principle. You should be able to get nice
21+ documentation for your web servers, and client libraries, without repeating
22+ yourself. You should not have to manually serialize and deserialize your
23+ resources, but only declare how to do those things *once per type*. If a
24+ bunch of your handlers take the same query parameters, you shouldn't have to
25+ repeat that logic for each handler, but instead just "apply" it to all of
26+ them at once. Your handlers shouldn't be where composition goes to die. And
27+ so on.
28+
29+- flexibility
30+
31+ If we haven't thought of your use case, it should still be easily
32+ achievable. If you want to use templating library X, go ahead. Forms? Do
33+ them however you want, but without difficulty. We're not opinionated.
34+
35+- separation of concerns
36+
37+ Your handlers and your HTTP logic should be separate. True to the philosphy
38+ at the core of HTTP and REST, with *servant* your handlers return normal
39+ Haskell datatypes - that's the resource. And then from a description of your
40+ API, *servant* handles the *presentation* (i.e., the Content-Types). But
41+ that's just one example.
42+
43+- type safety
44+
45+ Want to be sure your API meets a specification? Your compiler can check
46+ that for you. Links you can be sure exist? You got it.
47+
48+To stick true to these principles, we do things a little differently than you
49+might expect. The core idea is *reifying the description of your API*. Once
50+reified, everything follows. We think we might be the first web framework to
51+reify API descriptions in an extensible way. We're pretty sure we're the first
52+to reify it as *types*.
53+
54+To be able to write a webservice you only need to read the first two sections,
55+but the goal of this document being to get you started with servant, we also
56+cover the couple of ways you can extend servant for a great good.
57+
58+Tutorial
59+---------
60+
61+.. toctree::
62+ :maxdepth: 2
63+
64+ api-type.lhs
65+ server.lhs
66+ client.lhs
67+ javascript.lhs
68+ docs.lhs
tutorial/javascript.lhsnew file+175
@@ -0,0 +1,175 @@
1+---
2+title: Deriving Javascript functions to query an API
3+toc: true
4+---
5+
6+We will now see how *servant* lets you turn an API type into javascript
7+functions that you can call to query a webservice. The derived code assumes you
8+use *jQuery* but you could very easily adapt the code to generate ajax requests
9+based on vanilla javascript or another library than *jQuery*.
10+
11+For this, we will consider a simple page divided in two parts. At the top, we
12+will have a search box that lets us search in a list of Haskell books by
13+author/title with a list of results that gets updated every time we enter or
14+remove a character, while at the bottom we will be able to see the classical
15+[probabilistic method to approximate
16+pi](http://en.wikipedia.org/wiki/Approximations_of_%CF%80#Summing_a_circle.27s_area),
17+using a webservice to get random points. Finally, we will serve an HTML file
18+along with a couple of Javascript files, among which one that's automatically
19+generated from the API type and which will provide ready-to-use functions to
20+query your API.
21+
22+The source for this tutorial section is a literate haskell file, so first we
23+need to have some language extensions and imports:
24+
25+> {-# LANGUAGE DataKinds #-}
26+> {-# LANGUAGE DeriveGeneric #-}
27+> {-# LANGUAGE OverloadedStrings #-}
28+> {-# LANGUAGE TypeOperators #-}
29+>
30+> module Javascript where
31+>
32+> import Control.Monad.IO.Class
33+> import Data.Aeson
34+> import Data.Proxy
35+> import Data.Text (Text)
36+> import qualified Data.Text as T
37+> import GHC.Generics
38+> import Language.Javascript.JQuery
39+> import Network.Wai
40+> import Servant
41+> import Servant.JQuery
42+> import System.Random
43+
44+Now let's have the API type(s) and the accompanying datatypes.
45+
46+> type API = "point" :> Get '[JSON] Point
47+> :<|> "books" :> QueryParam "q" Text :> Get '[JSON] (Search Book)
48+>
49+> type API' = API :<|> Raw
50+>
51+> data Point = Point
52+> { x :: Double
53+> , y :: Double
54+> } deriving Generic
55+>
56+> instance ToJSON Point
57+>
58+> data Search a = Search
59+> { query :: Text
60+> , results :: [a]
61+> } deriving Generic
62+>
63+> mkSearch :: Text -> [a] -> Search a
64+> mkSearch = Search
65+>
66+> instance ToJSON a => ToJSON (Search a)
67+>
68+> data Book = Book
69+> { author :: Text
70+> , title :: Text
71+> , year :: Int
72+> } deriving Generic
73+>
74+> instance ToJSON Book
75+>
76+> book :: Text -> Text -> Int -> Book
77+> book = Book
78+
79+We need a "book database". For the purpose of this guide, let's restrict ourselves to the following books.
80+
81+> books :: [Book]
82+> books =
83+> [ book "Paul Hudak" "The Haskell School of Expression: Learning Functional Programming through Multimedia" 2000
84+> , book "Bryan O'Sullivan, Don Stewart, and John Goerzen" "Real World Haskell" 2008
85+> , book "Miran Lipovača" "Learn You a Haskell for Great Good!" 2011
86+> , book "Graham Hutton" "Programming in Haskell" 2007
87+> , book "Simon Marlow" "Parallel and Concurrent Programming in Haskell" 2013
88+> , book "Richard Bird" "Introduction to Functional Programming using Haskell" 1998
89+> ]
90+
91+Now, given an optional search string `q`, we want to perform a case insensitive search in that list of books. We're obviously not going to try and implement the best possible algorithm, this is out of scope for this tutorial. The following simple linear scan will do, given how small our list is.
92+
93+> searchBook :: Monad m => Maybe Text -> m (Search Book)
94+> searchBook Nothing = return (mkSearch "" books)
95+> searchBook (Just q) = return (mkSearch q books')
96+>
97+> where books' = filter (\b -> q' `T.isInfixOf` T.toLower (author b)
98+> || q' `T.isInfixOf` T.toLower (title b)
99+> )
100+> books
101+> q' = T.toLower q
102+
103+We also need an endpoint that generates random points `(x, y)` with `-1 <= x,y <= 1`. The code below uses [random](http://hackage.haskell.org/package/random)'s `System.Random`.
104+
105+> randomPoint :: MonadIO m => m Point
106+> randomPoint = liftIO . getStdRandom $ \g ->
107+> let (rx, g') = randomR (-1, 1) g
108+> (ry, g'') = randomR (-1, 1) g'
109+> in (Point rx ry, g'')
110+
111+If we add static file serving, our server is now complete.
112+
113+> api :: Proxy API
114+> api = Proxy
115+>
116+> api' :: Proxy API'
117+> api' = Proxy
118+>
119+> server :: Server API
120+> server = randomPoint
121+> :<|> searchBook
122+>
123+> server' :: Server API'
124+> server' = server
125+> :<|> serveDirectory "tutorial/t9"
126+>
127+> app :: Application
128+> app = serve api' server'
129+
130+Why two different API types, proxies and servers though? Simply because we don't want to generate javascript functions for the `Raw` part of our API type, so we need a `Proxy` for our API type `API'` without its `Raw` endpoint.
131+
132+Very similarly to how one can derive haskell functions, we can derive the javascript with just a simple function call to `jsForAPI` from `Servant.JQuery`.
133+
134+> apiJS :: String
135+> apiJS = jsForAPI api
136+
137+This `String` contains 2 Javascript functions:
138+
139+``` javascript
140+
141+function getpoint(onSuccess, onError)
142+{
143+ $.ajax(
144+ { url: '/point'
145+ , success: onSuccess
146+ , error: onError
147+ , method: 'GET'
148+ });
149+}
150+
151+function getbooks(q, onSuccess, onError)
152+{
153+ $.ajax(
154+ { url: '/books' + '?q=' + encodeURIComponent(q)
155+ , success: onSuccess
156+ , error: onError
157+ , method: 'GET'
158+ });
159+}
160+```
161+
162+Right before starting up our server, we will need to write this `String` to a file, say `api.js`, along with a copy of the *jQuery* library, as provided by the [js-jquery](http://hackage.haskell.org/package/js-jquery) package.
163+
164+> writeJSFiles :: IO ()
165+> writeJSFiles = do
166+> writeFile "getting-started/gs9/api.js" apiJS
167+> jq <- readFile =<< Language.Javascript.JQuery.file
168+> writeFile "getting-started/gs9/jq.js" jq
169+
170+And we're good to go. Start the server with `dist/build/tutorial/tutorial 9` and go to `http://localhost:8081/`. Start typing in the name of one of the authors in our database or part of a book title, and check out how long it takes to approximate &pi; using the method mentioned above.
171+
172+<div style="text-align: center;">
173+ <p><a href="/tutorial/client.html">Previous page: Deriving Haskell functions to query an API</a></p>
174+ <p><a href="/tutorial/docs.html">Next page: Generating documentation for APIs</a></p>
175+</div>
tutorial/requirements.txtnew file+25
@@ -0,0 +1,25 @@
1+alabaster==0.7.7
2+argh==0.26.1
3+Babel==2.2.0
4+backports-abc==0.4
5+backports.ssl-match-hostname==3.5.0.1
6+certifi==2015.11.20.1
7+CommonMark==0.5.4
8+docutils==0.12
9+Jinja2==2.8
10+livereload==2.4.1
11+MarkupSafe==0.23
12+pathtools==0.1.2
13+Pygments==2.1
14+pytz==2015.7
15+PyYAML==3.11
16+recommonmark==0.4.0
17+singledispatch==3.4.0.3
18+six==1.10.0
19+snowballstemmer==1.2.1
20+Sphinx==1.3.4
21+sphinx-autobuild==0.5.2
22+sphinx-rtd-theme==0.1.9
23+tornado==4.3
24+watchdog==0.8.3
25+wheel==0.26.0
tutorial/server.lhsnew file+1176
@@ -0,0 +1,1176 @@
1+---
2+title: Serving an API
3+toc: true
4+---
5+
6+Enough chit-chat about type-level combinators and representing an API as a
7+type. Can we have a webservice already?
8+
9+If you want to follow along with the code and run the examples while you read this guide:
10+
11+``` bash
12+cabal get servant-examples
13+cd servant-examples-<VERSION>
14+cabal sandbox init
15+cabal install --dependencies-only
16+cabal configure && cabal build
17+```
18+
19+This will produce a `tutorial` executable in the
20+`dist/build/tutorial` directory that just runs the example corresponding
21+to the number specified as a command line argument:
22+
23+``` bash
24+$ dist/build/tutorial/tutorial
25+Usage: tutorial N
26+ where N is the number of the example you want to run.
27+```
28+
29+A first example
30+===============
31+
32+Equipped with some basic knowledge about the way we represent API, let's now write our first webservice.
33+
34+The source for this tutorial section is a literate haskell file, so first we
35+need to have some language extensions and imports:
36+
37+> {-# LANGUAGE DataKinds #-}
38+> {-# LANGUAGE DeriveGeneric #-}
39+> {-# LANGUAGE FlexibleInstances #-}
40+> {-# LANGUAGE GeneralizedNewtypeDeriving #-}
41+> {-# LANGUAGE MultiParamTypeClasses #-}
42+> {-# LANGUAGE OverloadedStrings #-}
43+> {-# LANGUAGE ScopedTypeVariables #-}
44+> {-# LANGUAGE TypeOperators #-}
45+>
46+> module Server where
47+>
48+> import Control.Monad.IO.Class
49+> import Control.Monad.Reader
50+> import Control.Monad.Trans.Either
51+> import Data.Aeson
52+> import Data.Aeson.Types
53+> import Data.Attoparsec.ByteString
54+> import Data.ByteString (ByteString)
55+> import Data.Int
56+> import Data.List
57+> import Data.String.Conversions
58+> import Data.Time.Calendar
59+> import GHC.Generics
60+> import Lucid
61+> import Network.HTTP.Media ((//), (/:))
62+> import Network.Wai
63+> import Network.Wai.Handler.Warp
64+> import Servant
65+> import System.Directory
66+> import Text.Blaze
67+> import Text.Blaze.Html.Renderer.Utf8
68+> import qualified Data.Aeson.Parser
69+> import qualified Text.Blaze.Html
70+
71+``` haskell
72+{-# LANGUAGE TypeFamilies #-}
73+```
74+
75+**Important**: the `Servant` module comes from the *servant-server* package, the one that lets us run webservers that implement a particular API type. It reexports all the types from the *servant* package that let you declare API types as well as everything you need to turn your request handlers into a fully-fledged webserver. This means that in your applications, you can just add *servant-server* as a dependency, import `Servant` and not worry about anything else.
76+
77+We will write a server that will serve the following API.
78+
79+> type UserAPI1 = "users" :> Get '[JSON] [User]
80+
81+Here's what we would like to see when making a GET request to `/users`.
82+
83+``` javascript
84+[ {"name": "Isaac Newton", "age": 372, "email": "isaac@newton.co.uk", "registration_date": "1683-03-01"}
85+, {"name": "Albert Einstein", "age": 136, "email": "ae@mc2.org", "registration_date": "1905-12-01"}
86+]
87+```
88+
89+Now let's define our `User` data type and write some instances for it.
90+
91+> data User = User
92+> { name :: String
93+> , age :: Int
94+> , email :: String
95+> , registration_date :: Day
96+> } deriving (Eq, Show, Generic)
97+>
98+> instance ToJSON User
99+
100+Nothing funny going on here. But we now can define our list of two users.
101+
102+> users1 :: [User]
103+> users1 =
104+> [ User "Isaac Newton" 372 "isaac@newton.co.uk" (fromGregorian 1683 3 1)
105+> , User "Albert Einstein" 136 "ae@mc2.org" (fromGregorian 1905 12 1)
106+> ]
107+
108+Let's also write our API type.
109+
110+``` haskell
111+type UserAPI1 = "users" :> Get '[JSON] [User]
112+```
113+
114+We can now take care of writing the actual webservice that will handle requests
115+to such an API. This one will be very simple, being reduced to just a single
116+endpoint. The type of the web application is determined by the API type,
117+through a *type family* named `Server`. (Type families are just functions that
118+take types as input and return types.) The `Server` type family will compute
119+the right type that a bunch of request handlers should have just from the
120+corresponding API type.
121+
122+The first thing to know about the `Server` type family is that behind the
123+scenes it will drive the routing, letting you focus only on the business
124+logic. The second thing to know is that for each endpoint, your handlers will
125+by default run in the `EitherT ServantErr IO` monad. This is overridable very
126+easily, as explained near the end of this guide. Third thing, the type of the
127+value returned in that monad must be the same as the second argument of the
128+HTTP method combinator used for the corresponding endpoint. In our case, it
129+means we must provide a handler of type `EitherT ServantErr IO [User]`. Well,
130+we have a monad, let's just `return` our list:
131+
132+> server1 :: Server UserAPI1
133+> server1 = return users1
134+
135+That's it. Now we can turn `server` into an actual webserver using [wai](http://hackage.haskell.org/package/wai) and [warp](http://hackage.haskell.org/package/warp):
136+
137+> userAPI :: Proxy UserAPI1
138+> userAPI = Proxy
139+>
140+> -- 'serve' comes from servant and hands you a WAI Application,
141+> -- which you can think of as an "abstract" web application,
142+> -- not yet a webserver.
143+> app1 :: Application
144+> app1 = serve userAPI server1
145+
146+The `userAPI` bit is, alas, boilerplate (we need it to guide type inference).
147+But that's about as much boilerplate as you get.
148+
149+And we're done! Let's run our webservice on the port 8081.
150+
151+> main :: IO ()
152+> main = run 8081 app1
153+
154+You can put this all into a file or just grab [servant's
155+repo](http://github.com/haskell-servant/servant) and look at the
156+*servant-examples* directory. The code we have just explored is in
157+*tutorial/T1.hs*, runnable with
158+`dist/build/tutorial/tutorial 1`.
159+
160+If you run it, you can go to `http://localhost:8081/users` in your browser or
161+query it with curl and you see:
162+
163+``` bash
164+$ curl http://localhost:8081/users
165+[{"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"}]
166+```
167+
168+More endpoints
169+==============
170+
171+What if we want more than one endpoint? Let's add `/albert` and `/isaac` to view the corresponding users encoded in JSON.
172+
173+> type UserAPI2 = "users" :> Get '[JSON] [User]
174+> :<|> "albert" :> Get '[JSON] User
175+> :<|> "isaac" :> Get '[JSON] User
176+
177+And let's adapt our code a bit.
178+
179+> isaac :: User
180+> isaac = User "Isaac Newton" 372 "isaac@newton.co.uk" (fromGregorian 1683 3 1)
181+>
182+> albert :: User
183+> albert = User "Albert Einstein" 136 "ae@mc2.org" (fromGregorian 1905 12 1)
184+>
185+> users2 :: [User]
186+> users2 = [isaac, albert]
187+
188+Now, just like we separate the various endpoints in `UserAPI` with `:<|>`, we
189+are going to separate the handlers with `:<|>` too! They must be provided in
190+the same order as the one they appear in in the API type.
191+
192+> server2 :: Server UserAPI2
193+> server2 = return users2
194+> :<|> return albert
195+> :<|> return isaac
196+
197+And that's it! You can run this example with
198+`dist/build/tutorial/tutorial 2` and check out the data available
199+at `/users`, `/albert` and `/isaac`.
200+
201+From combinators to handler arguments
202+=====================================
203+
204+Fine, we can write trivial webservices easily, but none of the two above use
205+any "fancy" combinator from servant. Let's address this and use `QueryParam`,
206+`Capture` and `ReqBody` right away. You'll see how each occurence of these
207+combinators in an endpoint makes the corresponding handler receive an
208+argument of the appropriate type automatically. You don't have to worry about
209+manually looking up URL captures or query string parameters, or
210+decoding/encoding data from/to JSON. Never.
211+
212+We are going to use the following data types and functions to implement a server for `API`.
213+
214+> type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
215+> :<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
216+> :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email
217+>
218+> data Position = Position
219+> { x :: Int
220+> , y :: Int
221+> } deriving Generic
222+>
223+> instance ToJSON Position
224+>
225+> newtype HelloMessage = HelloMessage { msg :: String }
226+> deriving Generic
227+>
228+> instance ToJSON HelloMessage
229+>
230+> data ClientInfo = ClientInfo
231+> { clientName :: String
232+> , clientEmail :: String
233+> , clientAge :: Int
234+> , clientInterestedIn :: [String]
235+> } deriving Generic
236+>
237+> instance FromJSON ClientInfo
238+> instance ToJSON ClientInfo
239+>
240+> data Email = Email
241+> { from :: String
242+> , to :: String
243+> , subject :: String
244+> , body :: String
245+> } deriving Generic
246+>
247+> instance ToJSON Email
248+>
249+> emailForClient :: ClientInfo -> Email
250+> emailForClient c = Email from' to' subject' body'
251+>
252+> where from' = "great@company.com"
253+> to' = clientEmail c
254+> subject' = "Hey " ++ clientName c ++ ", we miss you!"
255+> body' = "Hi " ++ clientName c ++ ",\n\n"
256+> ++ "Since you've recently turned " ++ show (clientAge c)
257+> ++ ", have you checked out our latest "
258+> ++ intercalate ", " (clientInterestedIn c)
259+> ++ " products? Give us a visit!"
260+
261+We can implement handlers for the three endpoints:
262+
263+> server3 :: Server API
264+> server3 = position
265+> :<|> hello
266+> :<|> marketing
267+>
268+> where position :: Int -> Int -> EitherT ServantErr IO Position
269+> position x y = return (Position x y)
270+>
271+> hello :: Maybe String -> EitherT ServantErr IO HelloMessage
272+> hello mname = return . HelloMessage $ case mname of
273+> Nothing -> "Hello, anonymous coward"
274+> Just n -> "Hello, " ++ n
275+>
276+> marketing :: ClientInfo -> EitherT ServantErr IO Email
277+> marketing clientinfo = return (emailForClient clientinfo)
278+
279+Did you see that? The types for your handlers changed to be just what we
280+needed! In particular:
281+
282+ - a `Capture "something" a` becomes an argument of type `a` (for `position`);
283+ - a `QueryParam "something" a` becomes an argument of type `Maybe a` (because
284+an endpoint can technically be accessed without specifying any query
285+string parameter, we decided to "force" handlers to be aware that the
286+parameter might not always be there);
287+
288+ - a `ReqBody contentTypeList a` becomes an argument of type `a`;
289+
290+And that's it. You can see this example in action by running `dist/build/tutorial/tutorial 3`.
291+
292+``` bash
293+$ curl http://localhost:8081/position/1/2
294+{"x":1,"y":2}
295+$ curl http://localhost:8081/hello
296+{"msg":"Hello, anonymous coward"}
297+$ curl http://localhost:8081/hello?name=Alp
298+{"msg":"Hello, Alp"}
299+$ curl -X POST -d '{"name":"Alp Mestanogullari", "email" : "alp@foo.com", "age": 25, "interested_in": ["haskell", "mathematics"]}' -H 'Accept: application/json' -H 'Content-type: application/json' http://localhost:8081/marketing
300+{"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"}
301+```
302+
303+For reference, here's a list of some combinators from *servant* and for those
304+that get turned into arguments to the handlers, the type of the argument.
305+
306+ > - `Delete`, `Get`, `Patch`, `Post`, `Put`: these do not become arguments. They provide the return type of handlers, which usually is `EitherT ServantErr IO <something>`.
307+ > - `Capture "something" a` becomes an argument of type `a`.
308+ > - `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.
309+ > - `QueryFlag "something"` and `MatrixFlag "something"` get turned into arguments of type `Bool`.
310+ > - `QueryParams "something" a` and `MatrixParams "something" a` get turned into arguments of type `[a]`.
311+ > - `ReqBody contentTypes a` gets turned into an argument of type `a`.
312+
313+The `FromText`/`ToText` classes
314+===============================
315+
316+Wait... How does *servant* know how to decode the `Int`s from the URL? Or how
317+to decode a `ClientInfo` value from the request body? This is what this and the
318+following two sections address.
319+
320+`Capture`s and `QueryParam`s are represented by some textual value in URLs.
321+`Header`s are similarly represented by a pair of a header name and a
322+corresponding (textual) value in the request's "metadata". This is why we
323+decided to provide a pair of typeclasses, `FromText` and `ToText` which just
324+let you say that you can respectively *extract* or *encode* values of some type
325+*from*/*to* text. Here are the definitions:
326+
327+``` haskell
328+class FromText a where
329+ fromText :: Text -> Maybe a
330+
331+class ToText a where
332+ toText :: a -> Text
333+```
334+
335+And as long as the type that a `Capture`/`QueryParam`/`Header`/etc will be
336+decoded to provides a `FromText` instance, it will Just Work. *servant*
337+provides a decent number of instances, but here are some examples of defining
338+your own.
339+
340+> -- A typical enumeration
341+> data Direction
342+> = Up
343+> | Down
344+> | Left
345+> | Right
346+>
347+> instance FromText Direction where
348+> -- requires {-# LANGUAGE OverloadedStrings #-}
349+> fromText "up" = Just Up
350+> fromText "down" = Just Down
351+> fromText "left" = Just Server.Left
352+> fromText "right" = Just Server.Right
353+> fromText _ = Nothing
354+>
355+> instance ToText Direction where
356+> toText Up = "up"
357+> toText Down = "down"
358+> toText Server.Left = "left"
359+> toText Server.Right = "right"
360+>
361+> newtype UserId = UserId Int64
362+> deriving (FromText, ToText)
363+
364+or writing the instances by hand:
365+
366+``` haskell
367+instance FromText UserId where
368+ fromText = fmap UserId fromText
369+
370+instance ToText UserId where
371+ toText (UserId i) = toText i
372+```
373+
374+There's not much else to say about these classes. You will need instances for
375+them when using `Capture`, `QueryParam`, `QueryParams`, `MatrixParam`,
376+`MatrixParams` and `Header` with your types. You will need `FromText` instances
377+for server-side request handlers and `ToText` instances only when using
378+*servant-client*, as described in the [section about deriving haskell
379+functions to query an API](/tutorial/client.html).
380+
381+Using content-types with your data types
382+========================================
383+
384+The same principle was operating when decoding request bodies from JSON, and
385+responses *into* JSON. (JSON is just the running example - you can do this with
386+any content-type.)
387+
388+This section introduces a couple of typeclasses provided by *servant* that make
389+all of this work.
390+
391+The truth behind `JSON`
392+-----------------------
393+
394+What exactly is `JSON`? Like the 3 other content types provided out of the box
395+by *servant*, it's a really dumb data type.
396+
397+``` haskell
398+data JSON
399+data PlainText
400+data FormUrlEncoded
401+data OctetStream
402+```
403+
404+Obviously, this is not all there is to `JSON`, otherwise it would be quite
405+pointless. Like most of the data types in *servant*, `JSON` is mostly there as
406+a special *symbol* that's associated with encoding (resp. decoding) to (resp.
407+from) the *JSON* format. The way this association is performed can be
408+decomposed into two steps.
409+
410+The first step is to provide a proper
411+[`MediaType`](https://hackage.haskell.org/package/http-media-0.6.2/docs/Network-HTTP-Media.html)
412+representation for `JSON`, or for your own content types. If you look at the
413+haddocks from this link, you can see that we just have to specify
414+`application/json` using the appropriate functions. In our case, we can just
415+use `(//) :: ByteString -> ByteString -> MediaType`. The precise way to specify
416+the `MediaType` is to write an instance for the `Accept` class:
417+
418+``` haskell
419+-- for reference:
420+class Accept ctype where
421+ contentType :: Proxy ctype -> MediaType
422+
423+instance Accept JSON where
424+ contentType _ = "application" // "json"
425+```
426+
427+The second step is centered around the `MimeRender` and `MimeUnrender` classes.
428+These classes just let you specify a way to respectively encode and decode
429+values respectively into or from your content-type's representation.
430+
431+``` haskell
432+class Accept ctype => MimeRender ctype a where
433+ mimeRender :: Proxy ctype -> a -> ByteString
434+ -- alternatively readable as:
435+ mimeRender :: Proxy ctype -> (a -> ByteString)
436+```
437+
438+Given a content-type and some user type, `MimeRender` provides a function that
439+encodes values of type `a` to lazy `ByteString`s.
440+
441+In the case of `JSON`, this is easily dealt with! For any type `a` with a
442+`ToJSON` instance, we can render values of that type to JSON using
443+`Data.Aeson.encode`.
444+
445+``` haskell
446+instance ToJSON a => MimeRender JSON a where
447+ mimeRender _ = encode
448+```
449+
450+And now the `MimeUnrender` class, which lets us extract values from lazy
451+`ByteString`s, alternatively failing with an error string.
452+
453+``` haskell
454+class Accept ctype => MimeUnrender ctype a where
455+ mimeUnrender :: Proxy ctype -> ByteString -> Either String a
456+ -- alternatively:
457+ mimeUnrender :: Proxy ctype -> (ByteString -> Either String a)
458+```
459+
460+We don't have much work to do there either, `Data.Aeson.eitherDecode` is
461+precisely what we need. However, it only allows arrays and objects as toplevel
462+JSON values and this has proven to get in our way more than help us so we wrote
463+our own little function around *aeson* and *attoparsec* that allows any type of
464+JSON value at the toplevel of a "JSON document". Here's the definition in case
465+you are curious.
466+
467+> eitherDecodeLenient :: FromJSON a => ByteString -> Either String a
468+> eitherDecodeLenient input = do
469+> v :: Value <- parseOnly (Data.Aeson.Parser.value <* endOfInput) (cs input)
470+> parseEither parseJSON v
471+
472+This function is exactly what we need for our `MimeUnrender` instance.
473+
474+``` haskell
475+instance FromJSON a => MimeUnrender JSON a where
476+ mimeUnrender _ = eitherDecodeLenient
477+```
478+
479+And this is all the code that lets you use `JSON` for with `ReqBody`, `Get`,
480+`Post` and friends. We can check our understanding by implementing support
481+for an `HTML` content type, so that users of your webservice can access an
482+HTML representation of the data they want, ready to be included in any HTML
483+document, e.g. using [jQuery's `load` function](https://api.jquery.com/load/), simply by adding `Accept:
484+text/html` to their request headers.
485+
486+Case-studies: *servant-blaze* and *servant-lucid*
487+-------------------------------------------------
488+
489+These days, most of the haskellers who write their HTML UIs directly from
490+Haskell use either [blaze-html](http://hackage.haskell.org/package/blaze-html)
491+or [lucid](http://hackage.haskell.org/package/lucid). The best option for
492+*servant* is obviously to support both (and hopefully other templating
493+solutions!).
494+
495+> data HTMLLucid
496+
497+Once again, the data type is just there as a symbol for the encoding/decoding
498+functions, except that this time we will only worry about encoding since
499+*blaze-html* and *lucid* don't provide a way to extract data from HTML.
500+
501+Both packages also have the same `Accept` instance for their `HTMLLucid` type.
502+
503+> instance Accept HTMLLucid where
504+> contentType _ = "text" // "html" /: ("charset", "utf-8")
505+
506+Note that this instance uses the `(/:)` operator from *http-media* which lets
507+us specify additional information about a content-type, like the charset here.
508+
509+The rendering instances for both packages both call similar functions that take
510+types with an appropriate instance to an "abstract" HTML representation and
511+then write that to a `ByteString`.
512+
513+For *lucid*:
514+
515+> instance ToHtml a => MimeRender HTMLLucid a where
516+> mimeRender _ = renderBS . toHtml
517+>
518+> -- let's also provide an instance for lucid's
519+> -- 'Html' wrapper.
520+> instance MimeRender HTMLLucid (Html a) where
521+> mimeRender _ = renderBS
522+
523+For *blaze-html*:
524+
525+> -- For this tutorial to compile 'HTMLLucid' and 'HTMLBlaze' have to be
526+> -- distinct. Usually you would stick to one html rendering library and then
527+> -- you can go with one 'HTML' type.
528+> data HTMLBlaze
529+>
530+> instance Accept HTMLBlaze where
531+> contentType _ = "text" // "html" /: ("charset", "utf-8")
532+>
533+> instance ToMarkup a => MimeRender HTMLBlaze a where
534+> mimeRender _ = renderHtml . Text.Blaze.Html.toHtml
535+>
536+> -- while we're at it, just like for lucid we can
537+> -- provide an instance for rendering blaze's 'Html' type
538+> instance MimeRender HTMLBlaze Text.Blaze.Html.Html where
539+> mimeRender _ = renderHtml
540+
541+Both [servant-blaze](http://hackage.haskell.org/package/servant-blaze) and
542+[servant-lucid](http://hackage.haskell.org/package/servant-lucid) let you use
543+`HTMLLucid` in any content type list as long as you provide an instance of the
544+appropriate class (`ToMarkup` for *blaze-html*, `ToHtml` for *lucid*).
545+
546+We can now write webservice that uses *servant-lucid* to show the `HTMLLucid`
547+content type in action. First off, imports and pragmas as usual.
548+
549+We will be serving the following API:
550+
551+> type PersonAPI = "persons" :> Get '[JSON, HTMLLucid] [Person]
552+
553+where `Person` is defined as follows:
554+
555+> data Person = Person
556+> { firstName :: String
557+> , lastName :: String
558+> } deriving Generic -- for the JSON instance
559+>
560+> instance ToJSON Person
561+
562+Now, let's teach *lucid* how to render a `Person` as a row in a table, and then
563+a list of `Person`s as a table with a row per person.
564+
565+> -- HTML serialization of a single person
566+> instance ToHtml Person where
567+> toHtml person =
568+> tr_ $ do
569+> td_ (toHtml $ firstName person)
570+> td_ (toHtml $ lastName person)
571+>
572+> -- do not worry too much about this
573+> toHtmlRaw = toHtml
574+>
575+> -- HTML serialization of a list of persons
576+> instance ToHtml [Person] where
577+> toHtml persons = table_ $ do
578+> tr_ $ do
579+> th_ "first name"
580+> th_ "last name"
581+>
582+> -- this just calls toHtml on each person of the list
583+> -- and concatenates the resulting pieces of HTML together
584+> foldMap toHtml persons
585+>
586+> toHtmlRaw = toHtml
587+
588+We create some `Person` values and serve them as a list:
589+
590+> persons :: [Person]
591+> persons =
592+> [ Person "Isaac" "Newton"
593+> , Person "Albert" "Einstein"
594+> ]
595+>
596+> personAPI :: Proxy PersonAPI
597+> personAPI = Proxy
598+>
599+> server4 :: Server PersonAPI
600+> server4 = return persons
601+>
602+> app2 :: Application
603+> app2 = serve personAPI server4
604+
605+And we're good to go. You can run this example with `dist/build/tutorial/tutorial 4`.
606+
607+``` bash
608+ $ curl http://localhost:8081/persons
609+ [{"lastName":"Newton","firstName":"Isaac"},{"lastName":"Einstein","firstName":"Albert"}]
610+ $ curl -H 'Accept: text/html' http://localhost:8081/persons
611+ <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>
612+ # or just point your browser to http://localhost:8081/persons
613+```
614+
615+The `EitherT ServantErr IO` monad
616+=================================
617+
618+At the heart of the handlers is the monad they run in, namely `EitherT
619+ServantErr IO`. One might wonder: why this monad? The answer is that it is the
620+simplest monad with the following properties:
621+
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`);
625+- it lets us perform IO, which is absolutely vital since most webservices exist
626+as interfaces to databases that we interact with in `IO`;
627+
628+Let's recall some definitions.
629+
630+``` haskell
631+-- from the Prelude
632+data Either e a = Left e | Right a
633+
634+-- from the 'either' package at
635+-- http://hackage.haskell.org/package/either-4.3.3.2/docs/Control-Monad-Trans-Either.html
636+newtype EitherT e m a
637+ = EitherT { runEitherT :: m (Either e a) }
638+```
639+
640+In short, this means that a handler of type `EitherT ServantErr IO a` is simply
641+equivalent to a computation of type `IO (Either ServantErr a)`, that is, an IO
642+action that either returns an error or a result.
643+
644+The aforementioned `either` package is worth taking a look at. Perhaps most
645+importantly:
646+
647+``` haskell
648+left :: Monad m => e -> EitherT e m a
649+```
650+Allows you to return an error from your handler (whereas `return` is enough to
651+return a success).
652+
653+Most of what you'll be doing in your handlers is running some IO and,
654+depending on the result, you might sometimes want to throw an error of some
655+kind and abort early. The next two sections cover how to do just that.
656+
657+Performing IO
658+-------------
659+
660+Another important instance from the list above is `MonadIO m => MonadIO (EitherT e m)`. [`MonadIO`](http://hackage.haskell.org/package/transformers-0.4.3.0/docs/Control-Monad-IO-Class.html) is a class from the *transformers* package defined as:
661+
662+``` haskell
663+class Monad m => MonadIO m where
664+ liftIO :: IO a -> m a
665+```
666+
667+Obviously, the `IO` monad provides a `MonadIO` instance. Hence for any type `e`, `EitherT e IO` has a `MonadIO` instance. So if you want to run any kind of IO computation in your handlers, just use `liftIO`:
668+
669+> type IOAPI1 = "myfile.txt" :> Get '[JSON] FileContent
670+>
671+> newtype FileContent = FileContent
672+> { content :: String }
673+> deriving Generic
674+>
675+> instance ToJSON FileContent
676+>
677+> server5 :: Server IOAPI1
678+> server5 = do
679+> filecontent <- liftIO (readFile "myfile.txt")
680+> return (FileContent filecontent)
681+
682+Failing, through `ServantErr`
683+-----------------------------
684+
685+If you want to explicitly fail at providing the result promised by an endpoint
686+using the appropriate HTTP status code (not found, unauthorized, etc) and some
687+error message, all you have to do is use the `left` function mentioned above
688+and provide it with the appropriate value of type `ServantErr`, which is
689+defined as:
690+
691+``` haskell
692+data ServantErr = ServantErr
693+ { errHTTPCode :: Int
694+ , errReasonPhrase :: String
695+ , errBody :: ByteString -- lazy bytestring
696+ , errHeaders :: [Header]
697+ }
698+```
699+
700+Many standard values are provided out of the box by the `Servant.Server`
701+module. If you want to use these values but add a body or some headers, just
702+use record update syntax:
703+
704+> failingHandler :: EitherT ServantErr IO ()
705+> failingHandler = left myerr
706+>
707+> where myerr :: ServantErr
708+> myerr = err503 { errBody = "Sorry dear user." }
709+
710+Here's an example where we return a customised 404-Not-Found error message in
711+the response body if "myfile.txt" isn't there:
712+
713+> server6 :: Server IOAPI1
714+> server6 = do
715+> exists <- liftIO (doesFileExist "myfile.txt")
716+> if exists
717+> then liftIO (readFile "myfile.txt") >>= return . FileContent
718+> else left custom404Err
719+>
720+> where custom404Err = err404 { errBody = "myfile.txt just isn't there, please leave this server alone." }
721+
722+Let's run this server (`dist/build/tutorial/tutorial 5`) and
723+query it, first without the file and then with the file.
724+
725+``` bash
726+ $ curl --verbose http://localhost:8081/myfile.txt
727+ [snip]
728+ * Connected to localhost (127.0.0.1) port 8081 (#0)
729+ > GET /myfile.txt HTTP/1.1
730+ > User-Agent: curl/7.30.0
731+ > Host: localhost:8081
732+ > Accept: */*
733+ >
734+ < HTTP/1.1 404 Not Found
735+ [snip]
736+ myfile.txt just isnt there, please leave this server alone.
737+
738+ $ echo Hello > myfile.txt
739+
740+ $ curl --verbose http://localhost:8081/myfile.txt
741+ [snip]
742+ * Connected to localhost (127.0.0.1) port 8081 (#0)
743+ > GET /myfile.txt HTTP/1.1
744+ > User-Agent: curl/7.30.0
745+ > Host: localhost:8081
746+ > Accept: */*
747+ >
748+ < HTTP/1.1 200 OK
749+ [snip]
750+ < Content-Type: application/json
751+ [snip]
752+ {"content":"Hello\n"}
753+```
754+
755+Response headers
756+================
757+
758+To add headers to your response, use [addHeader](http://hackage.haskell.org/package/servant-0.4.4/docs/Servant-API-ResponseHeaders.html).
759+Note that this changes the type of your API, as we can see in the following example:
760+
761+> type MyHandler = Get '[JSON] (Headers '[Header "X-An-Int" Int] User)
762+>
763+> myHandler :: Server MyHandler
764+> myHandler = return $ addHeader 1797 albert
765+
766+
767+Serving static files
768+====================
769+
770+*servant-server* also provides a way to just serve the content of a directory
771+under some path in your web API. As mentioned earlier in this document, the
772+`Raw` combinator can be used in your APIs to mean "plug here any WAI
773+application". Well, servant-server provides a function to get a file and
774+directory serving WAI application, namely:
775+
776+``` haskell
777+-- exported by Servant and Servant.Server
778+serveDirectory :: FilePath -> Server Raw
779+```
780+
781+`serveDirectory`'s argument must be a path to a valid directory. You can see an
782+example below, runnable with `dist/build/tutorial/tutorial 6`
783+(you **must** run it from within the *servant-examples/* directory!), which is
784+a webserver that serves the various bits of code covered in this
785+getting-started.
786+
787+The API type will be the following.
788+
789+> type CodeAPI = "code" :> Raw
790+
791+And the server:
792+
793+> codeAPI :: Proxy CodeAPI
794+> codeAPI = Proxy
795+
796+> server7 :: Server CodeAPI
797+> server7 = serveDirectory "tutorial"
798+>
799+> app3 :: Application
800+> app3 = serve codeAPI server7
801+
802+This server will match any request whose path starts with `/code` and will look for a file at the path described by the rest of the request path, inside the *tutorial/* directory of the path you run the program from.
803+
804+In other words:
805+
806+- If a client requests `/code/foo.txt`, the server will look for a file at `./tutorial/foo.txt` (and fail)
807+- If a client requests `/code/T1.hs`, the server will look for a file at `./tutorial/T1.hs` (and succeed)
808+- If a client requests `/code/foo/bar/baz/movie.mp4`, the server will look for a file at `./tutorial/foo/bar/baz/movie.mp4` (and fail)
809+
810+Here is our little server in action.
811+
812+``` haskell
813+$ curl http://localhost:8081/code/T1.hs
814+{-# LANGUAGE DataKinds #-}
815+{-# LANGUAGE TypeFamilies #-}
816+{-# LANGUAGE DeriveGeneric #-}
817+{-# LANGUAGE TypeOperators #-}
818+module T1 where
819+
820+import Data.Aeson
821+import Data.Time.Calendar
822+import GHC.Generics
823+import Network.Wai
824+import Servant
825+
826+data User = User
827+ { name :: String
828+ , age :: Int
829+ , email :: String
830+ , registration_date :: Day
831+ } deriving (Eq, Show, Generic)
832+
833+-- orphan ToJSON instance for Day. necessary to derive one for User
834+instance ToJSON Day where
835+ -- display a day in YYYY-mm-dd format
836+ toJSON d = toJSON (showGregorian d)
837+
838+instance ToJSON User
839+
840+type UserAPI = "users" :> Get '[JSON] [User]
841+
842+users :: [User]
843+users =
844+ [ User "Isaac Newton" 372 "isaac@newton.co.uk" (fromGregorian 1683 3 1)
845+ , User "Albert Einstein" 136 "ae@mc2.org" (fromGregorian 1905 12 1)
846+ ]
847+
848+userAPI :: Proxy UserAPI
849+userAPI = Proxy
850+
851+server :: Server UserAPI
852+server = return users
853+
854+app :: Application
855+app = serve userAPI server
856+$ curl http://localhost:8081/code/tutorial.hs
857+import Network.Wai
858+import Network.Wai.Handler.Warp
859+import System.Environment
860+
861+import qualified T1
862+import qualified T2
863+import qualified T3
864+import qualified T4
865+import qualified T5
866+import qualified T6
867+import qualified T7
868+import qualified T9
869+import qualified T10
870+
871+app :: String -> (Application -> IO ()) -> IO ()
872+app n f = case n of
873+ "1" -> f T1.app
874+ "2" -> f T2.app
875+ "3" -> f T3.app
876+ "4" -> f T4.app
877+ "5" -> f T5.app
878+ "6" -> f T6.app
879+ "7" -> f T7.app
880+ "8" -> f T3.app
881+ "9" -> T9.writeJSFiles >> f T9.app
882+ "10" -> f T10.app
883+ _ -> usage
884+
885+main :: IO ()
886+main = do
887+ args <- getArgs
888+ case args of
889+ [n] -> app n (run 8081)
890+ _ -> usage
891+
892+usage :: IO ()
893+usage = do
894+ putStrLn "Usage:\t tutorial N"
895+ putStrLn "\t\twhere N is the number of the example you want to run."
896+
897+$ curl http://localhost:8081/foo
898+not found
899+```
900+
901+Nested APIs
902+===========
903+
904+Let's see how you can define APIs in a modular way, while avoiding repetition. Consider this simple example:
905+
906+> type UserAPI3 = -- view the user with given userid, in JSON
907+> Capture "userid" Int :> Get '[JSON] User
908+>
909+> :<|> -- delete the user with given userid. empty response
910+> Capture "userid" Int :> Delete '[] ()
911+
912+We can instead factor out the `userid`:
913+
914+> type UserAPI4 = Capture "userid" Int :>
915+> ( Get '[JSON] User
916+> :<|> Delete '[] ()
917+> )
918+
919+However, you have to be aware that this has an effect on the type of the corresponding `Server`:
920+
921+``` haskell
922+Server UserAPI3 = (Int -> EitherT ServantErr IO User)
923+ :<|> (Int -> EitherT ServantErr IO ())
924+
925+Server UserAPI4 = Int -> ( EitherT ServantErr IO User
926+ :<|> EitherT ServantErr IO ()
927+ )
928+```
929+
930+In the first case, each handler receives the *userid* argument. In the latter,
931+the whole `Server` takes the *userid* and has handlers that are just computations in `EitherT`, with no arguments. In other words:
932+
933+> server8 :: Server UserAPI3
934+> server8 = getUser :<|> deleteUser
935+>
936+> where getUser :: Int -> EitherT ServantErr IO User
937+> getUser _userid = error "..."
938+>
939+> deleteUser :: Int -> EitherT ServantErr IO ()
940+> deleteUser _userid = error "..."
941+>
942+> -- notice how getUser and deleteUser
943+> -- have a different type! no argument anymore,
944+> -- the argument directly goes to the whole Server
945+> server9 :: Server UserAPI4
946+> server9 userid = getUser userid :<|> deleteUser userid
947+>
948+> where getUser :: Int -> EitherT ServantErr IO User
949+> getUser = error "..."
950+>
951+> deleteUser :: Int -> EitherT ServantErr IO ()
952+> deleteUser = error "..."
953+
954+Note that there's nothing special about `Capture` that lets you "factor it out": this can be done with any combinator. Here are a few examples of APIs with a combinator factored out for which we can write a perfectly valid `Server`.
955+
956+> -- we just factor out the "users" path fragment
957+> type API1 = "users" :>
958+> ( Get '[JSON] [User] -- user listing
959+> :<|> Capture "userid" Int :> Get '[JSON] User -- view a particular user
960+> )
961+>
962+> -- we factor out the Request Body
963+> type API2 = ReqBody '[JSON] User :>
964+> ( Get '[JSON] User -- just display the same user back, don't register it
965+> :<|> Post '[JSON] () -- register the user. empty response
966+> )
967+>
968+> -- we factor out a Header
969+> type API3 = Header "Authorization" Token :>
970+> ( Get '[JSON] SecretData -- get some secret data, if authorized
971+> :<|> ReqBody '[JSON] SecretData :> Post '[] () -- add some secret data, if authorized
972+> )
973+>
974+> newtype Token = Token ByteString
975+> newtype SecretData = SecretData ByteString
976+
977+This approach lets you define APIs modularly and assemble them all into one big API type only at the end.
978+
979+> type UsersAPI =
980+> Get '[JSON] [User] -- list users
981+> :<|> ReqBody '[JSON] User :> Post '[] () -- add a user
982+> :<|> Capture "userid" Int :>
983+> ( Get '[JSON] User -- view a user
984+> :<|> ReqBody '[JSON] User :> Put '[] () -- update a user
985+> :<|> Delete '[] () -- delete a user
986+> )
987+>
988+> usersServer :: Server UsersAPI
989+> usersServer = getUsers :<|> newUser :<|> userOperations
990+>
991+> where getUsers :: EitherT ServantErr IO [User]
992+> getUsers = error "..."
993+>
994+> newUser :: User -> EitherT ServantErr IO ()
995+> newUser = error "..."
996+>
997+> userOperations userid =
998+> viewUser userid :<|> updateUser userid :<|> deleteUser userid
999+>
1000+> where
1001+> viewUser :: Int -> EitherT ServantErr IO User
1002+> viewUser = error "..."
1003+>
1004+> updateUser :: Int -> User -> EitherT ServantErr IO ()
1005+> updateUser = error "..."
1006+>
1007+> deleteUser :: Int -> EitherT ServantErr IO ()
1008+> deleteUser = error "..."
1009+
1010+> type ProductsAPI =
1011+> Get '[JSON] [Product] -- list products
1012+> :<|> ReqBody '[JSON] Product :> Post '[] () -- add a product
1013+> :<|> Capture "productid" Int :>
1014+> ( Get '[JSON] Product -- view a product
1015+> :<|> ReqBody '[JSON] Product :> Put '[] () -- update a product
1016+> :<|> Delete '[] () -- delete a product
1017+> )
1018+>
1019+> data Product = Product { productId :: Int }
1020+>
1021+> productsServer :: Server ProductsAPI
1022+> productsServer = getProducts :<|> newProduct :<|> productOperations
1023+>
1024+> where getProducts :: EitherT ServantErr IO [Product]
1025+> getProducts = error "..."
1026+>
1027+> newProduct :: Product -> EitherT ServantErr IO ()
1028+> newProduct = error "..."
1029+>
1030+> productOperations productid =
1031+> viewProduct productid :<|> updateProduct productid :<|> deleteProduct productid
1032+>
1033+> where
1034+> viewProduct :: Int -> EitherT ServantErr IO Product
1035+> viewProduct = error "..."
1036+>
1037+> updateProduct :: Int -> Product -> EitherT ServantErr IO ()
1038+> updateProduct = error "..."
1039+>
1040+> deleteProduct :: Int -> EitherT ServantErr IO ()
1041+> deleteProduct = error "..."
1042+
1043+> type CombinedAPI = "users" :> UsersAPI
1044+> :<|> "products" :> ProductsAPI
1045+>
1046+> server10 :: Server CombinedAPI
1047+> server10 = usersServer :<|> productsServer
1048+
1049+Finally, we can realize the user and product APIs are quite similar and abstract that away:
1050+
1051+> -- API for values of type 'a'
1052+> -- indexed by values of type 'i'
1053+> type APIFor a i =
1054+> Get '[JSON] [a] -- list 'a's
1055+> :<|> ReqBody '[JSON] a :> Post '[] () -- add an 'a'
1056+> :<|> Capture "id" i :>
1057+> ( Get '[JSON] a -- view an 'a' given its "identifier" of type 'i'
1058+> :<|> ReqBody '[JSON] a :> Put '[] () -- update an 'a'
1059+> :<|> Delete '[] () -- delete an 'a'
1060+> )
1061+>
1062+> -- Build the appropriate 'Server'
1063+> -- given the handlers of the right type.
1064+> serverFor :: EitherT ServantErr IO [a] -- handler for listing of 'a's
1065+> -> (a -> EitherT ServantErr IO ()) -- handler for adding an 'a'
1066+> -> (i -> EitherT ServantErr IO a) -- handler for viewing an 'a' given its identifier of type 'i'
1067+> -> (i -> a -> EitherT ServantErr IO ()) -- updating an 'a' with given id
1068+> -> (i -> EitherT ServantErr IO ()) -- deleting an 'a' given its id
1069+> -> Server (APIFor a i)
1070+> serverFor = error "..."
1071+> -- implementation left as an exercise. contact us on IRC
1072+> -- or the mailing list if you get stuck!
1073+
1074+Using another monad for your handlers
1075+=====================================
1076+
1077+Remember how `Server` turns combinators for HTTP methods into `EitherT ServantErr IO`? Well, actually, there's more to that. `Server` is actually a simple type synonym.
1078+
1079+``` haskell
1080+type Server api = ServerT api (EitherT ServantErr IO)
1081+```
1082+
1083+`ServerT` is the actual type family that computes the required types for the handlers that's part of the `HasServer` class. It's like `Server` except that it takes a third parameter which is the monad you want your handlers to run in, or more generally the return types of your handlers. This third parameter is used for specifying the return type of the handler for an endpoint, e.g when computing `ServerT (Get '[JSON] Person) SomeMonad`. The result would be `SomeMonad Person`.
1084+
1085+The first and main question one might have then is: how do we write handlers that run in another monad? How can we "bring back" the value from a given monad into something *servant* can understand?
1086+
1087+Natural transformations
1088+-----------------------
1089+
1090+If we have a function that gets us from an `m a` to an `n a`, for any `a`, what
1091+do we have?
1092+
1093+``` haskell
1094+newtype m :~> n = Nat { unNat :: forall a. m a -> n a}
1095+
1096+-- For example
1097+-- listToMaybeNat ::`[] :~> Maybe`
1098+-- listToMaybeNat = Nat listToMaybe -- from Data.Maybe
1099+```
1100+(`Nat` comes from "natural transformation", in case you're wondering.)
1101+
1102+So if you want to write handlers using another monad/type than `EitherT
1103+ServantErr IO`, say the `Reader String` monad, the first thing you have to
1104+prepare is a function:
1105+
1106+``` haskell
1107+readerToEither :: Reader String :~> EitherT ServantErr IO
1108+```
1109+
1110+Let's start with `readerToEither'`. We obviously have to run the `Reader`
1111+computation by supplying it with a `String`, like `"hi"`. We get an `a` out
1112+from that and can then just `return` it into `EitherT`. We can then just wrap
1113+that function with the `Nat` constructor to make it have the fancier type.
1114+
1115+> readerToEither' :: forall a. Reader String a -> EitherT ServantErr IO a
1116+> readerToEither' r = return (runReader r "hi")
1117+>
1118+> readerToEither :: Reader String :~> EitherT ServantErr IO
1119+> readerToEither = Nat readerToEither'
1120+
1121+We can write some simple webservice with the handlers running in `Reader String`.
1122+
1123+> type ReaderAPI = "a" :> Get '[JSON] Int
1124+> :<|> "b" :> Get '[JSON] String
1125+>
1126+> readerAPI :: Proxy ReaderAPI
1127+> readerAPI = Proxy
1128+>
1129+> readerServerT :: ServerT ReaderAPI (Reader String)
1130+> readerServerT = a :<|> b
1131+>
1132+> where a :: Reader String Int
1133+> a = return 1797
1134+>
1135+> b :: Reader String String
1136+> b = ask
1137+
1138+We unfortunately can't use `readerServerT` as an argument of `serve`, because
1139+`serve` wants a `Server ReaderAPI`, i.e., with handlers running in `EitherT
1140+ServantErr IO`. But there's a simple solution to this.
1141+
1142+Enter `enter`
1143+-------------
1144+
1145+That's right. We have just written `readerToEither`, which is exactly what we
1146+would need to apply to the results of all handlers to make the handlers have the
1147+right type for `serve`. Being cumbersome to do by hand, we provide a function
1148+`enter` which takes a natural transformation between two parametrized types `m`
1149+and `n` and a `ServerT someapi m`, and returns a `ServerT someapi n`.
1150+
1151+In our case, we can wrap up our little webservice by using `enter readerToEither` on our handlers.
1152+
1153+> readerServer :: Server ReaderAPI
1154+> readerServer = enter readerToEither readerServerT
1155+>
1156+> app4 :: Application
1157+> app4 = serve readerAPI readerServer
1158+
1159+And we can indeed see this webservice in action by running `dist/build/tutorial/tutorial 7`.
1160+
1161+``` bash
1162+$ curl http://localhost:8081/a
1163+1797
1164+$ curl http://localhost:8081/b
1165+"hi"
1166+```
1167+
1168+Conclusion
1169+==========
1170+
1171+You're now equipped to write any kind of webservice/web-application using *servant*. One thing not covered here is how to incorporate your own combinators and will be the topic of a page on the website. The rest of this document focuses on *servant-client*, *servant-jquery* and *servant-docs*.
1172+
1173+<div style="text-align: center;">
1174+ <p><a href="/tutorial/api-type.html">Previous page: A web API as a type</a></p>
1175+ <p><a href="/tutorial/client.html">Next page: Deriving Haskell functions to query an API</a></p>
1176+</div>