@@ -1,7 +1,4 @@
1−---
2−title: A web API as a type
3−toc: true
4−---
1+# A web API as a type
52
63The source for this tutorial section is a literate haskell file, so first we
74need to have some language extensions and imports:
@@ -25,8 +22,7 @@ Consider the following informal specification of an API:
2522
2623You *should* be able to formalize that. And then use the formalized version to
2724get you much of the way towards writing a web app. And all the way towards
28−getting some client libraries, and documentation (and in the future, who knows
29−- tests, HATEOAS, ...).
25+getting some client libraries, and documentation, and more.
3026
3127How would we describe it with servant? As mentioned earlier, an endpoint
3228description is a good old Haskell **type**:
@@ -45,22 +41,22 @@ data User = User {
4541Let's break that down:
4642
4743- `"users"` says that our endpoint will be accessible under `/users`;
48−- `QueryParam "sortby" SortBy`, where `SortBy` is defined by `data SortBy = Age
49−| Name`, says that the endpoint has a query string parameter named `sortby`
50−whose value will be extracted as a value of type `SortBy`.
44+- `QueryParam "sortby" SortBy`, where `SortBy` is defined by `data SortBy = Age | Name`,
45+ says that the endpoint has a query string parameter named `sortby`
46+ whose value will be extracted as a value of type `SortBy`.
5147- `Get '[JSON] [User]` says that the endpoint will be accessible through HTTP
52−GET requests, returning a list of users encoded as JSON. You will see
53−later how you can make use of this to make your data available under different
54−formats, the choice being made depending on the [Accept
55−header](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html) specified in
56−the client's request.
57−- the `:>` operator that separates the various "combinators" just lets you
58−sequence static path fragments, URL captures and other combinators. The
59−ordering only matters for static path fragments and URL captures. `"users" :>
60−"list-all" :> Get '[JSON] [User]`, equivalent to `/users/list-all`, is
61−obviously not the same as `"list-all" :> "users" :> Get '[JSON] [User]`, which
62−is equivalent to `/list-all/users`. This means that sometimes `:>` is somehow
63−equivalent to `/`, but sometimes it just lets you chain another combinator.
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.
6460
6561We can also describe APIs with multiple endpoints by using the `:<|>`
6662combinators. Here's an example:
@@ -74,11 +70,10 @@ type UserAPI2 = "users" :> "list-all" :> Get '[JSON] [User]
7470always write your own when you need it. Here's a quick overview of all the
7571combinators that servant comes with.
7672
77−Combinators
78−===========
73+## Combinators
74+
75+### Static strings
7976
80−Static strings
81−--------------
8277
8378As you've already seen, you can use type-level strings (enabled with the
8479`DataKinds` language extension) for static path fragments. Chaining
@@ -90,8 +85,8 @@ type UserAPI3 = "users" :> "list-all" :> "now" :> Get '[JSON] [User]
9085 -- /users/list-all/now
9186```
9287
93−`Delete`, `Get`, `Patch`, `Post` and `Put`
94−------------------------------------------
88+### `Delete`, `Get`, `Patch`, `Post` and `Put`
89+
9590
9691These 5 combinators are very similar except that they each describe a
9792different HTTP method. This is how they're declared
@@ -112,8 +107,8 @@ type UserAPI4 = "users" :> Get '[JSON] [User]
112107 :<|> "admins" :> Get '[JSON] [User]
113108```
114109
115−`Capture`
116−---------
110+### `Capture`
111+
117112
118113URL captures are parts of the URL that are variable and whose actual value is
119114captured and passed to the request handlers. In many web frameworks, you'll see
@@ -147,8 +142,7 @@ type UserAPI5 = "user" :> Capture "userid" Integer :> Get '[JSON] User
147142 -- equivalent to 'DELETE /user/:userid'
148143```
149144
150−`QueryParam`, `QueryParams`, `QueryFlag`, `MatrixParam`, `MatrixParams` and `MatrixFlag`
151−----------------------------------------------------------------------------------------
145+### `QueryParam`, `QueryParams`, `QueryFlag`, `MatrixParam`, `MatrixParams` and `MatrixFlag`
152146
153147`QueryParam`, `QueryParams` and `QueryFlag` are about query string
154148parameters, i.e., those parameters that come after the question mark
@@ -202,8 +196,7 @@ type UserAPI6 = "users" :> QueryParam "sortby" SortBy :> Get '[JSON] [User]
202196Again, your handlers don't have to deserialize these things (into, for example,
203197a `SortBy`). *servant* takes care of it.
204198
205−`ReqBody`
206−---------
199+### `ReqBody`
207200
208201Each HTTP request can carry some additional data that the server can use in its
209202*body*, and this data can be encoded in any format -- as long as the server
@@ -240,8 +233,8 @@ type UserAPI7 = "users" :> ReqBody '[JSON] User :> Post '[JSON] User
240233 -- - returns a User encoded in JSON
241234```
242235
243−Request `Header`s
244−-----------------
236+### Request `Header`s
237+
245238
246239Request headers are used for various purposes, from caching to carrying
247240auth-related data. They consist of a header name and an associated value. An
@@ -263,8 +256,7 @@ the client to send the request.
263256type UserAPI8 = "users" :> Header "User-Agent" Text :> Get '[JSON] [User]
264257```
265258
266−Content types
267−-------------
259+### Content types
268260
269261So far, whenever we have used a combinator that carries a list of content
270262types, we've always specified `'[JSON]`. However, *servant* lets you use several
@@ -286,8 +278,7 @@ that everyone uses, we decided to release 2 packages, *servant-lucid* and
286278We will further explain how these content types and your data types can play
287279together in the [section about serving an API](/tutorial/server.html).
288280
289−Response `Headers`
290−------------------
281+### Response `Headers`
291282
292283Just like an HTTP request, the response generated by a webserver can carry
293284headers too. *servant* provides a `Headers` combinator that carries a list of
@@ -305,8 +296,7 @@ response, you could write it as below:
305296type UserAPI10 = "users" :> Get '[JSON] (Headers '[Header "User-Count" Integer] [User])
306297```
307298
308−Interoperability with other WAI `Application`s: `Raw`
309−-----------------------------------------------------
299+### Interoperability with other WAI `Application`s: `Raw`
310300
311301Finally, we also include a combinator named `Raw` that can be used for two reasons:
312302