git.iko.soy/typeable/servant
on master help sign in
Fix cabal file, stack.yaml, and sources.txt
f601cbfJulian K. Arni
doc/tutorial/api-type.lhs → doc/tutorial/ApiType.lhsrenamed+31−41
@@ -1,7 +1,4 @@
1−---
2−title: A web API as a type
1+# A web API as a type
3−toc: true
4−---
5
2
6The source for this tutorial section is a literate haskell file, so first we
3The source for this tutorial section is a literate haskell file, so first we
7need to have some language extensions and imports:
4need to have some language extensions and imports:
@@ -25,8 +22,7 @@ Consider the following informal specification of an API:
25
22
26You *should* be able to formalize that. And then use the formalized version to
23You *should* be able to formalize that. And then use the formalized version to
27get you much of the way towards writing a web app. And all the way towards
24get 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
25+getting some client libraries, and documentation, and more.
29−- tests, HATEOAS, ...).
30
26
31How would we describe it with servant? As mentioned earlier, an endpoint
27How would we describe it with servant? As mentioned earlier, an endpoint
32description is a good old Haskell **type**:
28description is a good old Haskell **type**:
@@ -45,22 +41,22 @@ data User = User {
45Let's break that down:
41Let's break that down:
46
42
47- `"users"` says that our endpoint will be accessible under `/users`;
43- `"users"` says that our endpoint will be accessible under `/users`;
48−- `QueryParam "sortby" SortBy`, where `SortBy` is defined by `data SortBy = Age
44+- `QueryParam "sortby" SortBy`, where `SortBy` is defined by `data SortBy = Age | Name`,
49−| Name`, says that the endpoint has a query string parameter named `sortby`
45+ says that the endpoint has a query string parameter named `sortby`
50−whose value will be extracted as a value of type `SortBy`.
46+ whose value will be extracted as a value of type `SortBy`.
51- `Get '[JSON] [User]` says that the endpoint will be accessible through HTTP
47- `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
48+ 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
49+ 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
50+ formats, the choice being made depending on the [Accept
55−header](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html) specified in
51+ header](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html) specified in
56−the client's request.
52+ the client's request.
57−- the `:>` operator that separates the various "combinators" just lets you
53+- The `:>` operator that separates the various "combinators" just lets you
58−sequence static path fragments, URL captures and other combinators. The
54+ sequence static path fragments, URL captures and other combinators. The
59−ordering only matters for static path fragments and URL captures. `"users" :>
55+ ordering only matters for static path fragments and URL captures. `"users" :>
60−"list-all" :> Get '[JSON] [User]`, equivalent to `/users/list-all`, is
56+ "list-all" :> Get '[JSON] [User]`, equivalent to `/users/list-all`, is
61−obviously not the same as `"list-all" :> "users" :> Get '[JSON] [User]`, which
57+ 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
58+ is equivalent to `/list-all/users`. This means that sometimes `:>` is somehow
63−equivalent to `/`, but sometimes it just lets you chain another combinator.
59+ equivalent to `/`, but sometimes it just lets you chain another combinator.
64
60
65We can also describe APIs with multiple endpoints by using the `:<|>`
61We can also describe APIs with multiple endpoints by using the `:<|>`
66combinators. Here's an example:
62combinators. Here's an example:
@@ -74,11 +70,10 @@ type UserAPI2 = "users" :> "list-all" :> Get '[JSON] [User]
74always write your own when you need it. Here's a quick overview of all the
70always write your own when you need it. Here's a quick overview of all the
75combinators that servant comes with.
71combinators that servant comes with.
76
72
77−Combinators
73+## Combinators
78−===========
74+
75+### Static strings
79
76
80−Static strings
81−--------------
82
77
83As you've already seen, you can use type-level strings (enabled with the
78As you've already seen, you can use type-level strings (enabled with the
84`DataKinds` language extension) for static path fragments. Chaining
79`DataKinds` language extension) for static path fragments. Chaining
@@ -90,8 +85,8 @@ type UserAPI3 = "users" :> "list-all" :> "now" :> Get '[JSON] [User]
90 -- /users/list-all/now
85 -- /users/list-all/now
91```
86```
92
87
93−`Delete`, `Get`, `Patch`, `Post` and `Put`
88+### `Delete`, `Get`, `Patch`, `Post` and `Put`
94−------------------------------------------
89+
95
90
96These 5 combinators are very similar except that they each describe a
91These 5 combinators are very similar except that they each describe a
97different HTTP method. This is how they're declared
92different HTTP method. This is how they're declared
@@ -112,8 +107,8 @@ type UserAPI4 = "users" :> Get '[JSON] [User]
112 :<|> "admins" :> Get '[JSON] [User]
107 :<|> "admins" :> Get '[JSON] [User]
113```
108```
114
109
115−`Capture`
110+### `Capture`
116−---------
111+
117
112
118URL captures are parts of the URL that are variable and whose actual value is
113URL captures are parts of the URL that are variable and whose actual value is
119captured and passed to the request handlers. In many web frameworks, you'll see
114captured 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
147 -- equivalent to 'DELETE /user/:userid'
142 -- equivalent to 'DELETE /user/:userid'
148```
143```
149
144
150−`QueryParam`, `QueryParams`, `QueryFlag`, `MatrixParam`, `MatrixParams` and `MatrixFlag`
145+### `QueryParam`, `QueryParams`, `QueryFlag`, `MatrixParam`, `MatrixParams` and `MatrixFlag`
151−----------------------------------------------------------------------------------------
152
146
153`QueryParam`, `QueryParams` and `QueryFlag` are about query string
147`QueryParam`, `QueryParams` and `QueryFlag` are about query string
154parameters, i.e., those parameters that come after the question mark
148parameters, i.e., those parameters that come after the question mark
@@ -202,8 +196,7 @@ type UserAPI6 = "users" :> QueryParam "sortby" SortBy :> Get '[JSON] [User]
202Again, your handlers don't have to deserialize these things (into, for example,
196Again, your handlers don't have to deserialize these things (into, for example,
203a `SortBy`). *servant* takes care of it.
197a `SortBy`). *servant* takes care of it.
204
198
205−`ReqBody`
199+### `ReqBody`
206−---------
207
200
208Each HTTP request can carry some additional data that the server can use in its
201Each HTTP request can carry some additional data that the server can use in its
209*body*, and this data can be encoded in any format -- as long as the server
202*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
240 -- - returns a User encoded in JSON
233 -- - returns a User encoded in JSON
241```
234```
242
235
243−Request `Header`s
236+### Request `Header`s
244−-----------------
237+
245
238
246Request headers are used for various purposes, from caching to carrying
239Request headers are used for various purposes, from caching to carrying
247auth-related data. They consist of a header name and an associated value. An
240auth-related data. They consist of a header name and an associated value. An
@@ -263,8 +256,7 @@ the client to send the request.
263type UserAPI8 = "users" :> Header "User-Agent" Text :> Get '[JSON] [User]
256type UserAPI8 = "users" :> Header "User-Agent" Text :> Get '[JSON] [User]
264```
257```
265
258
266−Content types
259+### Content types
267−-------------
268
260
269So far, whenever we have used a combinator that carries a list of content
261So far, whenever we have used a combinator that carries a list of content
270types, we've always specified `'[JSON]`. However, *servant* lets you use several
262types, 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
286We will further explain how these content types and your data types can play
278We will further explain how these content types and your data types can play
287together in the [section about serving an API](/tutorial/server.html).
279together in the [section about serving an API](/tutorial/server.html).
288
280
289−Response `Headers`
281+### Response `Headers`
290−------------------
291
282
292Just like an HTTP request, the response generated by a webserver can carry
283Just like an HTTP request, the response generated by a webserver can carry
293headers too. *servant* provides a `Headers` combinator that carries a list of
284headers too. *servant* provides a `Headers` combinator that carries a list of
@@ -305,8 +296,7 @@ response, you could write it as below:
305type UserAPI10 = "users" :> Get '[JSON] (Headers '[Header "User-Count" Integer] [User])
296type UserAPI10 = "users" :> Get '[JSON] (Headers '[Header "User-Count" Integer] [User])
306```
297```
307
298
308−Interoperability with other WAI `Application`s: `Raw`
299+### Interoperability with other WAI `Application`s: `Raw`
309−-----------------------------------------------------
310
300
311Finally, we also include a combinator named `Raw` that can be used for two reasons:
301Finally, we also include a combinator named `Raw` that can be used for two reasons:
312
302
doc/tutorial/client.lhs → doc/tutorial/Client.lhsrenamed

The content is the same.

doc/tutorial/docs.lhs → doc/tutorial/Docs.lhsrenamed

The content is the same.

doc/tutorial/javascript.lhs → doc/tutorial/Javascript.lhsrenamed

The content is the same.

doc/tutorial/server.lhs → doc/tutorial/Server.lhsrenamed

The content is the same.

doc/tutorial/tutorial.cabal+9−2
@@ -1,5 +1,5 @@
1name: tutorial
1name: tutorial
2−version: 0.1.0.0
2+version: 0.5
3synopsis: The servant tutorial
3synopsis: The servant tutorial
4-- description:
4-- description:
5homepage: http://haskell-servant.github.io/
5homepage: http://haskell-servant.github.io/
@@ -14,9 +14,16 @@ build-type: Simple
14cabal-version: >=1.10
14cabal-version: >=1.10
15
15
16library
16library
17− exposed-modules: api-type.lhs
17+ exposed-modules: ApiType
18+ , Client
19+ , Docs
20+ , Javascript
21+ , Server
18 -- other-modules:
22 -- other-modules:
19 -- other-extensions:
23 -- other-extensions:
20 build-depends: base >=4.8 && <4.9
24 build-depends: base >=4.8 && <4.9
25+ , text
26+ , servant
21 -- hs-source-dirs:
27 -- hs-source-dirs:
22 default-language: Haskell2010
28 default-language: Haskell2010
29+ ghc-options: -Wall -Werror -c -pgmL markdown-unlit
sources.txt−1
@@ -5,7 +5,6 @@ servant-docs
5servant-foreign
5servant-foreign
6servant-js
6servant-js
7servant-server
7servant-server
8−servant-examples
9servant-blaze
8servant-blaze
10servant-lucid
9servant-lucid
11servant-mock
10servant-mock
stack.yaml+1−1
@@ -7,12 +7,12 @@ packages:
7- servant-cassava/
7- servant-cassava/
8- servant-client/
8- servant-client/
9- servant-docs/
9- servant-docs/
10−- servant-examples/
11- servant-foreign/
10- servant-foreign/
12- servant-js/
11- servant-js/
13- servant-lucid/
12- servant-lucid/
14- servant-mock/
13- servant-mock/
15- servant-server/
14- servant-server/
15+- doc/tutorial
16extra-deps:
16extra-deps:
17- base-compat-0.9.0
17- base-compat-0.9.0
18- engine-io-wai-1.0.2
18- engine-io-wai-1.0.2