@@ -3,29 +3,10 @@
33Enough chit-chat about type-level combinators and representing an API as a
44type. Can we have a webservice already?
55
6−If you want to follow along with the code and run the examples while you read this guide:
7−
8−``` bash
9−cabal get servant-examples
10−cd servant-examples-<VERSION>
11−cabal sandbox init
12−cabal install --dependencies-only
13−cabal configure && cabal build
14−```
15−
16−This will produce a `tutorial` executable in the
17−`dist/build/tutorial` directory that just runs the example corresponding
18−to the number specified as a command line argument:
19−
20−``` bash
21−$ dist/build/tutorial/tutorial
22−Usage: tutorial N
23− where N is the number of the example you want to run.
24−```
25−
266## A first example
277
28−Equipped with some basic knowledge about the way we represent API, let's now write our first webservice.
8+Equipped with some basic knowledge about the way we represent API, let's now
9+write our first webservice.
2910
3011The source for this tutorial section is a literate haskell file, so first we
3112need to have some language extensions and imports:
@@ -72,7 +53,13 @@ import qualified Text.Blaze.Html
7253{-# LANGUAGE TypeFamilies #-}
7354```
7455
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.
56+**Important**: the `Servant` module comes from the *servant-server* package,
57+the one that lets us run webservers that implement a particular API type. It
58+reexports all the types from the *servant* package that let you declare API
59+types as well as everything you need to turn your request handlers into a
60+fully-fledged webserver. This means that in your applications, you can just add
61+*servant-server* as a dependency, import `Servant` and not worry about anything
62+else.
7663
7764We will write a server that will serve the following API.
7865
@@ -95,7 +82,7 @@ data User = User
9582 { name :: String
9683 , age :: Int
9784 , email :: String
98− , registrationDate :: Day
85+ , registration_date :: Day
9986 } deriving (Eq, Show, Generic)
10087
10188instance ToJSON User
@@ -140,7 +127,9 @@ server1 :: Server UserAPI1
140127server1 = return users1
141128```
142129
143−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):
130+That's it. Now we can turn `server` into an actual webserver using
131+[wai](http://hackage.haskell.org/package/wai) and
132+[warp](http://hackage.haskell.org/package/warp):
144133
145134``` haskell
146135userAPI :: Proxy UserAPI1
@@ -179,7 +168,8 @@ $ curl http://localhost:8081/users
179168
180169## More endpoints
181170
182−What if we want more than one endpoint? Let's add `/albert` and `/isaac` to view the corresponding users encoded in JSON.
171+What if we want more than one endpoint? Let's add `/albert` and `/isaac` to
172+view the corresponding users encoded in JSON.
183173
184174``` haskell
185175type UserAPI2 = "users" :> Get '[JSON] [User]
@@ -225,7 +215,8 @@ argument of the appropriate type automatically. You don't have to worry about
225215manually looking up URL captures or query string parameters, or
226216decoding/encoding data from/to JSON. Never.
227217
228−We are going to use the following data types and functions to implement a server for `API`.
218+We are going to use the following data types and functions to implement a
219+server for `API`.
229220
230221``` haskell
231222type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
@@ -307,7 +298,8 @@ parameter might not always be there);
307298
308299 - a `ReqBody contentTypeList a` becomes an argument of type `a`;
309300
310−And that's it. You can see this example in action by running `dist/build/tutorial/tutorial 3`.
301+And that's it. You can see this example in action by running
302+`dist/build/tutorial/tutorial 3`.
311303
312304``` bash
313305$ curl http://localhost:8081/position/1/2
@@ -474,8 +466,8 @@ And this is all the code that lets you use `JSON` for with `ReqBody`, `Get`,
474466`Post` and friends. We can check our understanding by implementing support
475467for an `HTML` content type, so that users of your webservice can access an
476468HTML representation of the data they want, ready to be included in any HTML
477−document, e.g. using [jQuery's `load` function](https://api.jquery.com/load/), simply by adding `Accept:
478−text/html` to their request headers.
469+document, e.g. using [jQuery's `load` function](https://api.jquery.com/load/),
470+simply by adding `Accept: text/html` to their request headers.
479471
480472### Case-studies: *servant-blaze* and *servant-lucid*
481473
@@ -766,7 +758,8 @@ query it, first without the file and then with the file.
766758
767759## Response headers
768760
769−To add headers to your response, use [addHeader](http://hackage.haskell.org/package/servant-0.4.4/docs/Servant-API-ResponseHeaders.html).
761+To add headers to your response, use
762+[addHeader](http://hackage.haskell.org/package/servant/docs/Servant-API-ResponseHeaders.html).
770763Note that this changes the type of your API, as we can see in the following example:
771764
772765``` haskell
@@ -824,9 +817,12 @@ for a file at the path described by the rest of the request path, inside the
824817
825818In other words:
826819
827−- If a client requests `/code/foo.txt`, the server will look for a file at `./tutorial/foo.txt` (and fail)
828−- If a client requests `/code/T1.hs`, the server will look for a file at `./tutorial/T1.hs` (and succeed)
829−- 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)
820+- If a client requests `/code/foo.txt`, the server will look for a file at
821+ `./tutorial/foo.txt` (and fail)
822+- If a client requests `/code/T1.hs`, the server will look for a file at
823+ `./tutorial/T1.hs` (and succeed)
824+- If a client requests `/code/foo/bar/baz/movie.mp4`, the server will look for
825+ a file at `./tutorial/foo/bar/baz/movie.mp4` (and fail)
830826
831827Here is our little server in action.
832828
@@ -921,7 +917,8 @@ not found
921917
922918## Nested APIs
923919
924−Let's see how you can define APIs in a modular way, while avoiding repetition. Consider this simple example:
920+Let's see how you can define APIs in a modular way, while avoiding repetition.
921+Consider this simple example:
925922
926923``` haskell
927924type UserAPI3 = -- view the user with given userid, in JSON
@@ -940,7 +937,8 @@ type UserAPI4 = Capture "userid" Int :>
940937 )
941938```
942939
943−However, you have to be aware that this has an effect on the type of the corresponding `Server`:
940+However, you have to be aware that this has an effect on the type of the
941+corresponding `Server`:
944942
945943``` haskell ignore
946944Server UserAPI3 = (Int -> ExceptT ServantErr IO User)
@@ -952,7 +950,8 @@ Server UserAPI4 = Int -> ( ExceptT ServantErr IO User
952950```
953951
954952In the first case, each handler receives the *userid* argument. In the latter,
955−the whole `Server` takes the *userid* and has handlers that are just computations in `ExceptT`, with no arguments. In other words:
953+the whole `Server` takes the *userid* and has handlers that are just
954+computations in `ExceptT`, with no arguments. In other words:
956955
957956``` haskell
958957server8 :: Server UserAPI3
@@ -977,7 +976,10 @@ server9 userid = getUser userid :<|> deleteUser userid
977976 deleteUser = error "..."
978977```
979978
980−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`.
979+Note that there's nothing special about `Capture` that lets you "factor it
980+out": this can be done with any combinator. Here are a few examples of APIs
981+with a combinator factored out for which we can write a perfectly valid
982+`Server`.
981983
982984``` haskell
983985-- we just factor out the "users" path fragment
@@ -1002,7 +1004,8 @@ newtype Token = Token ByteString
10021004newtype SecretData = SecretData ByteString
10031005```
10041006
1005−This approach lets you define APIs modularly and assemble them all into one big API type only at the end.
1007+This approach lets you define APIs modularly and assemble them all into one big
1008+API type only at the end.
10061009
10071010``` haskell
10081011type UsersAPI =
@@ -1080,7 +1083,8 @@ server10 :: Server CombinedAPI
10801083server10 = usersServer :<|> productsServer
10811084```
10821085
1083−Finally, we can realize the user and product APIs are quite similar and abstract that away:
1086+Finally, we can realize the user and product APIs are quite similar and
1087+abstract that away:
10841088
10851089``` haskell
10861090-- API for values of type 'a'
@@ -1109,15 +1113,25 @@ serverFor = error "..."
11091113
11101114## Using another monad for your handlers
11111115
1112−Remember how `Server` turns combinators for HTTP methods into `ExceptT ServantErr IO`? Well, actually, there's more to that. `Server` is actually a simple type synonym.
1116+Remember how `Server` turns combinators for HTTP methods into `ExceptT
1117+ServantErr IO`? Well, actually, there's more to that. `Server` is actually a
1118+simple type synonym.
11131119
11141120``` haskell ignore
11151121type Server api = ServerT api (ExceptT ServantErr IO)
11161122```
11171123
1118−`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`.
1124+`ServerT` is the actual type family that computes the required types for the
1125+handlers that's part of the `HasServer` class. It's like `Server` except that
1126+it takes a third parameter which is the monad you want your handlers to run in,
1127+or more generally the return types of your handlers. This third parameter is
1128+used for specifying the return type of the handler for an endpoint, e.g when
1129+computing `ServerT (Get '[JSON] Person) SomeMonad`. The result would be
1130+`SomeMonad Person`.
11191131
1120−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?
1132+The first and main question one might have then is: how do we write handlers
1133+that run in another monad? How can we "bring back" the value from a given monad
1134+into something *servant* can understand?
11211135
11221136### Natural transformations
11231137
@@ -1185,7 +1199,8 @@ right type for `serve`. Being cumbersome to do by hand, we provide a function
11851199`enter` which takes a natural transformation between two parametrized types `m`
11861200and `n` and a `ServerT someapi m`, and returns a `ServerT someapi n`.
11871201
1188−In our case, we can wrap up our little webservice by using `enter readerToEither` on our handlers.
1202+In our case, we can wrap up our little webservice by using `enter
1203+readerToEither` on our handlers.
11891204
11901205``` haskell
11911206readerServer :: Server ReaderAPI
@@ -1195,7 +1210,8 @@ app4 :: Application
11951210app4 = serve readerAPI EmptyConfig readerServer
11961211```
11971212
1198−And we can indeed see this webservice in action by running `dist/build/tutorial/tutorial 7`.
1213+And we can indeed see this webservice in action by running
1214+`dist/build/tutorial/tutorial 7`.
11991215
12001216``` bash
12011217$ curl http://localhost:8081/a
@@ -1206,9 +1222,7 @@ $ curl http://localhost:8081/b
12061222
12071223## Conclusion
12081224
1209−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*.
1210−
1211−<div style="text-align: center;">
1212− <p><a href="/tutorial/api-type.html">Previous page: A web API as a type</a></p>
1213− <p><a href="/tutorial/client.html">Next page: Deriving Haskell functions to query an API</a></p>
1214−</div>
1225+You're now equipped to write any kind of webservice/web-application using
1226+*servant*. One thing not covered here is how to incorporate your own
1227+combinators and will be the topic of a page on the website. The rest of this
1228+document focuses on *servant-client*, *servant-jquery* and *servant-docs*.