@@ -5,7 +5,7 @@ type. Can we have a webservice already?
6## A first example
6## A first example
8−Equipped with some basic knowledge about the way we represent API, let's now
8+Equipped with some basic knowledge about the way we represent APIs, let's now
9write our first webservice.
9write our first webservice.
11The source for this tutorial section is a literate haskell file, so first we
11The source for this tutorial section is a literate haskell file, so first we
@@ -26,7 +26,7 @@ module Server where
26import Prelude ()
26import Prelude ()
27import Prelude.Compat
27import Prelude.Compat
29−import Control.Monad.IO.Class
29+import Control.Monad.Except
30import Control.Monad.Reader
30import Control.Monad.Reader
31import Control.Monad.Trans.Except
31import Control.Monad.Trans.Except
32import Data.Aeson.Compat
32import Data.Aeson.Compat
@@ -34,6 +34,7 @@ import Data.Aeson.Types
34import Data.Attoparsec.ByteString
34import Data.Attoparsec.ByteString
35import Data.ByteString (ByteString)
35import Data.ByteString (ByteString)
36import Data.List
36import Data.List
37import Data.String.Conversions
38import Data.String.Conversions
38import Data.Time.Calendar
39import Data.Time.Calendar
39import GHC.Generics
40import GHC.Generics
@@ -49,16 +50,12 @@ import qualified Data.Aeson.Parser
49import qualified Text.Blaze.Html
50import qualified Text.Blaze.Html
53−{-# LANGUAGE TypeFamilies #-}
56−**Important**: the `Servant` module comes from the *servant-server* package,
53+**Important**: the `Servant` module comes from the **servant-server** package,
57the one that lets us run webservers that implement a particular API type. It
54the 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
55+reexports all the types from the **servant** package that let you declare API
59types as well as everything you need to turn your request handlers into a
56types as well as everything you need to turn your request handlers into a
60fully-fledged webserver. This means that in your applications, you can just add
57fully-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
58+**servant-server** as a dependency, import `Servant` and not worry about anything
64We will write a server that will serve the following API.
61We will write a server that will serve the following API.
@@ -154,9 +151,8 @@ main = run 8081 app1
155You can put this all into a file or just grab [servant's
152You can put this all into a file or just grab [servant's
156repo](http://github.com/haskell-servant/servant) and look at the
153repo](http://github.com/haskell-servant/servant) and look at the
157−*servant-examples* directory. The code we have just explored is in
154+*doc/tutorial* directory. This code (the source of this web page) is in
158−*tutorial/T1.hs*, runnable with
155+*doc/tutorial/Server.lhs*.
159−`dist/build/tutorial/tutorial 1`.
161If you run it, you can go to `http://localhost:8081/users` in your browser or
157If you run it, you can go to `http://localhost:8081/users` in your browser or
162query it with curl and you see:
158query it with curl and you see:
@@ -192,7 +188,7 @@ users2 = [isaac, albert]
193Now, just like we separate the various endpoints in `UserAPI` with `:<|>`, we
189Now, just like we separate the various endpoints in `UserAPI` with `:<|>`, we
194are going to separate the handlers with `:<|>` too! They must be provided in
190are going to separate the handlers with `:<|>` too! They must be provided in
195−the same order as the one they appear in in the API type.
191+the same order as in in the API type.
197``` haskell
193``` haskell
198server2 :: Server UserAPI2
194server2 :: Server UserAPI2
@@ -201,9 +197,8 @@ server2 = return users2
201 :<|> return isaac
197 :<|> return isaac
204−And that's it! You can run this example with
200+And that's it! You can run this example in the same way that we showed for
205−`dist/build/tutorial/tutorial 2` and check out the data available
206−at `/users`, `/albert` and `/isaac`.
201+`server1` and check out the data available at `/users`, `/albert` and `/isaac`.
208## From combinators to handler arguments
203## From combinators to handler arguments
@@ -298,8 +293,7 @@ parameter might not always be there);
299 - a `ReqBody contentTypeList a` becomes an argument of type `a`;
294 - a `ReqBody contentTypeList a` becomes an argument of type `a`;
301−And that's it. You can see this example in action by running
296+And that's it. Here's the example in action:
302−`dist/build/tutorial/tutorial 3`.
305$ curl http://localhost:8081/position/1/2
299$ curl http://localhost:8081/position/1/2
@@ -312,19 +306,18 @@ $ curl -X POST -d '{"name":"Alp Mestanogullari", "email" : "alp@foo.com", "age":
312{"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"}
306{"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"}
315−For reference, here's a list of some combinators from *servant* and for those
309+For reference, here's a list of some combinators from **servant**:
316−that get turned into arguments to the handlers, the type of the argument.
318 > - `Delete`, `Get`, `Patch`, `Post`, `Put`: these do not become arguments. They provide the return type of handlers, which usually is `ExceptT ServantErr IO <something>`.
311 > - `Delete`, `Get`, `Patch`, `Post`, `Put`: these do not become arguments. They provide the return type of handlers, which usually is `ExceptT ServantErr IO <something>`.
319 > - `Capture "something" a` becomes an argument of type `a`.
312 > - `Capture "something" a` becomes an argument of type `a`.
320− > - `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.
313+ > - `QueryParam "something" a`, `Header "something" a` all become arguments of type `Maybe a`, because there might be no value at all specified by the client for these.
321− > - `QueryFlag "something"` and `MatrixFlag "something"` get turned into arguments of type `Bool`.
314+ > - `QueryFlag "something"` gets turned into an argument of type `Bool`.
322− > - `QueryParams "something" a` and `MatrixParams "something" a` get turned into arguments of type `[a]`.
315+ > - `QueryParams "something" a` gets turned into an argument of type `[a]`.
323 > - `ReqBody contentTypes a` gets turned into an argument of type `a`.
316 > - `ReqBody contentTypes a` gets turned into an argument of type `a`.
325## The `FromHttpApiData`/`ToHttpApiData` classes
318## The `FromHttpApiData`/`ToHttpApiData` classes
327−Wait... How does *servant* know how to decode the `Int`s from the URL? Or how
320+Wait... How does **servant** know how to decode the `Int`s from the URL? Or how
328to decode a `ClientInfo` value from the request body? This is what this and the
321to decode a `ClientInfo` value from the request body? This is what this and the
329following two sections address.
322following two sections address.
@@ -333,7 +326,7 @@ following two sections address.
333corresponding (textual) value in the request's "metadata". How types are
326corresponding (textual) value in the request's "metadata". How types are
334decoded from headers, captures, and query params is expressed in a class
327decoded from headers, captures, and query params is expressed in a class
335`FromHttpApiData` (from the package
328`FromHttpApiData` (from the package
336−[*http-api-data*](http://hackage.haskell.org/package/http-api-data)):
329+[**http-api-data**](http://hackage.haskell.org/package/http-api-data)):
338``` haskell ignore
331``` haskell ignore
339class FromHttpApiData a where
332class FromHttpApiData a where
@@ -355,15 +348,15 @@ As you can see, as long as you provide either `parseUrlPiece` (for `Capture`s)
355or `parseQueryParam` (for `QueryParam`s), the other methods will be defined in
348or `parseQueryParam` (for `QueryParam`s), the other methods will be defined in
356terms of this.
349terms of this.
358−*http-api-data* provides a decent number of instances, helpers for defining new
351+**http-api-data** provides a decent number of instances, helpers for defining new
359ones, and wonderful documentation.
352ones, and wonderful documentation.
361There's not much else to say about these classes. You will need instances for
354There's not much else to say about these classes. You will need instances for
362them when using `Capture`, `QueryParam`, `QueryParams`, and `Header` with your
355them when using `Capture`, `QueryParam`, `QueryParams`, and `Header` with your
363types. You will need `FromHttpApiData` instances for server-side request
356types. You will need `FromHttpApiData` instances for server-side request
364handlers and `ToHttpApiData` instances only when using
357handlers and `ToHttpApiData` instances only when using
365−*servant-client*, as described in the [section about deriving haskell
358+**servant-client**, as described in the [section about deriving haskell
366−functions to query an API](/tutorial/client.html).
359+functions to query an API](Client.html).
368## Using content-types with your data types
361## Using content-types with your data types
@@ -371,14 +364,15 @@ The same principle was operating when decoding request bodies from JSON, and
371responses *into* JSON. (JSON is just the running example - you can do this with
364responses *into* JSON. (JSON is just the running example - you can do this with
372any content-type.)
365any content-type.)
374−This section introduces a couple of typeclasses provided by *servant* that make
367+This section introduces a couple of typeclasses provided by **servant** that make
375all of this work.
368all of this work.
377### The truth behind `JSON`
370### The truth behind `JSON`
373+What exactly is `JSON` (the type as used in `Get '[JSON] User`)? Like the 3
380−What exactly is `JSON`? Like the 3 other content types provided out of the box
374+other content-types provided out of the box by **servant**, it's a really dumb
381−by *servant*, it's a really dumb data type.
375+data type.
383``` haskell ignore
377``` haskell ignore
@@ -388,14 +382,15 @@ data OctetStream
390Obviously, this is not all there is to `JSON`, otherwise it would be quite
384Obviously, this is not all there is to `JSON`, otherwise it would be quite
391−pointless. Like most of the data types in *servant*, `JSON` is mostly there as
385+pointless. Like most of the data types in **servant**, `JSON` is mostly there as
392a special *symbol* that's associated with encoding (resp. decoding) to (resp.
386a special *symbol* that's associated with encoding (resp. decoding) to (resp.
393from) the *JSON* format. The way this association is performed can be
387from) the *JSON* format. The way this association is performed can be
394decomposed into two steps.
388decomposed into two steps.
396The first step is to provide a proper
390The first step is to provide a proper
397−[`MediaType`](https://hackage.haskell.org/package/http-media-0.6.2/docs/Network-HTTP-Media.html)
392+[**http-media**](https://hackage.haskell.org/package/http-media-0.6.2/docs/Network-HTTP-Media.html))
398−representation for `JSON`, or for your own content types. If you look at the
393+representation for `JSON`, or for your own content-types. If you look at the
399haddocks from this link, you can see that we just have to specify
394haddocks from this link, you can see that we just have to specify
400`application/json` using the appropriate functions. In our case, we can just
395`application/json` using the appropriate functions. In our case, we can just
401use `(//) :: ByteString -> ByteString -> MediaType`. The precise way to specify
396use `(//) :: ByteString -> ByteString -> MediaType`. The precise way to specify
@@ -411,14 +406,14 @@ instance Accept JSON where
413The second step is centered around the `MimeRender` and `MimeUnrender` classes.
408The second step is centered around the `MimeRender` and `MimeUnrender` classes.
414−These classes just let you specify a way to respectively encode and decode
409+These classes just let you specify a way to encode and decode
415−values respectively into or from your content-type's representation.
410+values into or from your content-type's representation.
417``` haskell ignore
412``` haskell ignore
418class Accept ctype => MimeRender ctype a where
413class Accept ctype => MimeRender ctype a where
419− mimeRender :: Proxy ctype -> a -> ByteString
414+ mimeRender :: Proxy ctype -> a -> ByteString
420 -- alternatively readable as:
415 -- alternatively readable as:
421− mimeRender :: Proxy ctype -> (a -> ByteString)
416+ mimeRender :: Proxy ctype -> (a -> ByteString)
424Given a content-type and some user type, `MimeRender` provides a function that
419Given a content-type and some user type, `MimeRender` provides a function that
@@ -444,7 +439,7 @@ class Accept ctype => MimeUnrender ctype a where
444We don't have much work to do there either, `Data.Aeson.eitherDecode` is
439We don't have much work to do there either, `Data.Aeson.eitherDecode` is
445precisely what we need. However, it only allows arrays and objects as toplevel
440precisely what we need. However, it only allows arrays and objects as toplevel
446JSON values and this has proven to get in our way more than help us so we wrote
441JSON values and this has proven to get in our way more than help us so we wrote
447−our own little function around *aeson* and *attoparsec* that allows any type of
442+our own little function around **aeson** and **attoparsec** that allows any type of
448JSON value at the toplevel of a "JSON document". Here's the definition in case
443JSON value at the toplevel of a "JSON document". Here's the definition in case
449you are curious.
444you are curious.
@@ -462,20 +457,20 @@ instance FromJSON a => MimeUnrender JSON a where
462 mimeUnrender _ = eitherDecodeLenient
457 mimeUnrender _ = eitherDecodeLenient
465−And this is all the code that lets you use `JSON` for with `ReqBody`, `Get`,
460+And this is all the code that lets you use `JSON` with `ReqBody`, `Get`,
466`Post` and friends. We can check our understanding by implementing support
461`Post` and friends. We can check our understanding by implementing support
467−for an `HTML` content type, so that users of your webservice can access an
462+for an `HTML` content-type, so that users of your webservice can access an
468HTML representation of the data they want, ready to be included in any HTML
463HTML representation of the data they want, ready to be included in any HTML
469document, e.g. using [jQuery's `load` function](https://api.jquery.com/load/),
464document, e.g. using [jQuery's `load` function](https://api.jquery.com/load/),
470simply by adding `Accept: text/html` to their request headers.
465simply by adding `Accept: text/html` to their request headers.
472−### Case-studies: *servant-blaze* and *servant-lucid*
467+### Case-studies: **servant-blaze** and **servant-lucid**
474These days, most of the haskellers who write their HTML UIs directly from
469These days, most of the haskellers who write their HTML UIs directly from
475−Haskell use either [blaze-html](http://hackage.haskell.org/package/blaze-html)
470+Haskell use either [**blaze-html**](http://hackage.haskell.org/package/blaze-html)
476−or [lucid](http://hackage.haskell.org/package/lucid). The best option for
471+or [**lucid**](http://hackage.haskell.org/package/lucid). The best option for
477−*servant* is obviously to support both (and hopefully other templating
472+**servant** is obviously to support both (and hopefully other templating
478−solutions!).
473+solutions!). We're first going to look at **lucid**:
480``` haskell
475``` haskell
481data HTMLLucid
476data HTMLLucid
@@ -483,24 +478,20 @@ data HTMLLucid
484Once again, the data type is just there as a symbol for the encoding/decoding
479Once again, the data type is just there as a symbol for the encoding/decoding
485functions, except that this time we will only worry about encoding since
480functions, except that this time we will only worry about encoding since
486−*blaze-html* and *lucid* don't provide a way to extract data from HTML.
481+**lucid** doesn't provide a way to extract data from HTML.
488−Both packages also have the same `Accept` instance for their `HTMLLucid` type.
490``` haskell
483``` haskell
491instance Accept HTMLLucid where
484instance Accept HTMLLucid where
492 contentType _ = "text" // "html" /: ("charset", "utf-8")
485 contentType _ = "text" // "html" /: ("charset", "utf-8")
495−Note that this instance uses the `(/:)` operator from *http-media* which lets
488+Note that this instance uses the `(/:)` operator from **http-media** which lets
496us specify additional information about a content-type, like the charset here.
489us specify additional information about a content-type, like the charset here.
498−The rendering instances for both packages both call similar functions that take
491+The rendering instances call similar functions that take
499types with an appropriate instance to an "abstract" HTML representation and
492types with an appropriate instance to an "abstract" HTML representation and
500then write that to a `ByteString`.
493then write that to a `ByteString`.
504``` haskell
495``` haskell
505instance ToHtml a => MimeRender HTMLLucid a where
496instance ToHtml a => MimeRender HTMLLucid a where
506 mimeRender _ = renderBS . toHtml
497 mimeRender _ = renderBS . toHtml
@@ -511,7 +502,7 @@ instance MimeRender HTMLLucid (Html a) where
511 mimeRender _ = renderBS
502 mimeRender _ = renderBS
514−For *blaze-html*:
505+For **blaze-html** everything works very similarly:
516``` haskell
507``` haskell
517-- For this tutorial to compile 'HTMLLucid' and 'HTMLBlaze' have to be
508-- For this tutorial to compile 'HTMLLucid' and 'HTMLBlaze' have to be
@@ -531,15 +522,13 @@ instance MimeRender HTMLBlaze Text.Blaze.Html.Html where
531 mimeRender _ = renderHtml
522 mimeRender _ = renderHtml
534−Both [servant-blaze](http://hackage.haskell.org/package/servant-blaze) and
525+Both [**servant-blaze**](http://hackage.haskell.org/package/servant-blaze) and
535−[servant-lucid](http://hackage.haskell.org/package/servant-lucid) let you use
526+[**servant-lucid**](http://hackage.haskell.org/package/servant-lucid) let you use
536−`HTMLLucid` in any content type list as long as you provide an instance of the
527+`HTMLLucid` and `HTMLBlaze` in any content-type list as long as you provide an instance of the
537−appropriate class (`ToMarkup` for *blaze-html*, `ToHtml` for *lucid*).
528+appropriate class (`ToMarkup` for **blaze-html**, `ToHtml` for **lucid**).
539−We can now write webservice that uses *servant-lucid* to show the `HTMLLucid`
540−content type in action. First off, imports and pragmas as usual.
530+We can now write a webservice that uses **servant-lucid** to show the `HTMLLucid`
542−We will be serving the following API:
531+content-type in action. We will be serving the following API:
544``` haskell
533``` haskell
545type PersonAPI = "persons" :> Get '[JSON, HTMLLucid] [Person]
534type PersonAPI = "persons" :> Get '[JSON, HTMLLucid] [Person]
@@ -556,7 +545,7 @@ data Person = Person
556instance ToJSON Person
545instance ToJSON Person
559−Now, let's teach *lucid* how to render a `Person` as a row in a table, and then
548+Now, let's teach **lucid** how to render a `Person` as a row in a table, and then
560a list of `Person`s as a table with a row per person.
549a list of `Person`s as a table with a row per person.
562``` haskell
551``` haskell
@@ -600,10 +589,10 @@ server4 :: Server PersonAPI
600server4 = return people
589server4 = return people
602app2 :: Application
591app2 :: Application
603−app2 = serve personAPI EmptyConfig server4
592+app2 = serve personAPI server4
606−And we're good to go. You can run this example with `dist/build/tutorial/tutorial 4`.
595+And we're good to go:
609 $ curl http://localhost:8081/persons
598 $ curl http://localhost:8081/persons
@@ -616,23 +605,21 @@ And we're good to go. You can run this example with `dist/build/tutorial/tutoria
616## The `ExceptT ServantErr IO` monad
605## The `ExceptT ServantErr IO` monad
618At the heart of the handlers is the monad they run in, namely `ExceptT
607At the heart of the handlers is the monad they run in, namely `ExceptT
609+([haddock documentation for `ExceptT`](http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#t:ExceptT)).
619−ServantErr IO`. One might wonder: why this monad? The answer is that it is the
610+One might wonder: why this monad? The answer is that it is the
620simplest monad with the following properties:
611simplest monad with the following properties:
622−- it lets us both return a successful result (with the `Right` branch of
613+- it lets us both return a successful result (using `return`)
623−`Either`) or "fail" with a descriptive error (with the `Left` branch of
614+or "fail" with a descriptive error (using `throwError`);
625- it lets us perform IO, which is absolutely vital since most webservices exist
615- it lets us perform IO, which is absolutely vital since most webservices exist
626−as interfaces to databases that we interact with in `IO`;
616+as interfaces to databases that we interact with in `IO`.
628Let's recall some definitions.
618Let's recall some definitions.
630``` haskell ignore
620``` haskell ignore
632−data Either e a = Left e | Right a
634-- from the 'mtl' package at
621-- from the 'mtl' package at
635−newtype ExceptT e m a = ExceptT ( m (Either e a) )
622+newtype ExceptT e m a = ExceptT (m (Either e a))
638In short, this means that a handler of type `ExceptT ServantErr IO a` is simply
625In short, this means that a handler of type `ExceptT ServantErr IO a` is simply
@@ -654,14 +641,14 @@ kind and abort early. The next two sections cover how to do just that.
654Another important instance from the list above is `MonadIO m => MonadIO
641Another important instance from the list above is `MonadIO m => MonadIO
655(ExceptT e m)`.
642(ExceptT e m)`.
656[`MonadIO`](http://hackage.haskell.org/package/transformers-0.4.3.0/docs/Control-Monad-IO-Class.html)
643[`MonadIO`](http://hackage.haskell.org/package/transformers-0.4.3.0/docs/Control-Monad-IO-Class.html)
657−is a class from the *transformers* package defined as:
644+is a class from the **transformers** package defined as:
659``` haskell ignore
646``` haskell ignore
660class Monad m => MonadIO m where
647class Monad m => MonadIO m where
661 liftIO :: IO a -> m a
648 liftIO :: IO a -> m a
664−Obviously, the `IO` monad provides a `MonadIO` instance. Hence for any type
651+The `IO` monad provides a `MonadIO` instance. Hence for any type
665`e`, `ExceptT e IO` has a `MonadIO` instance. So if you want to run any kind of
652`e`, `ExceptT e IO` has a `MonadIO` instance. So if you want to run any kind of
666IO computation in your handlers, just use `liftIO`:
653IO computation in your handlers, just use `liftIO`:
@@ -684,7 +671,7 @@ server5 = do
685If you want to explicitly fail at providing the result promised by an endpoint
672If you want to explicitly fail at providing the result promised by an endpoint
686using the appropriate HTTP status code (not found, unauthorized, etc) and some
673using 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
674+error message, all you have to do is use the `throwError` function mentioned above
688and provide it with the appropriate value of type `ServantErr`, which is
675and provide it with the appropriate value of type `ServantErr`, which is
689defined as:
676defined as:
@@ -703,7 +690,7 @@ use record update syntax:
704``` haskell
691``` haskell
705failingHandler :: ExceptT ServantErr IO ()
692failingHandler :: ExceptT ServantErr IO ()
706−failingHandler = throwE myerr
693+failingHandler = throwError myerr
708 where myerr :: ServantErr
695 where myerr :: ServantErr
709 myerr = err503 { errBody = "Sorry dear user." }
696 myerr = err503 { errBody = "Sorry dear user." }
@@ -718,13 +705,12 @@ server6 = do
718 exists <- liftIO (doesFileExist "myfile.txt")
705 exists <- liftIO (doesFileExist "myfile.txt")
719 if exists
706 if exists
720 then liftIO (readFile "myfile.txt") >>= return . FileContent
707 then liftIO (readFile "myfile.txt") >>= return . FileContent
721− else throwE custom404Err
708+ else throwError custom404Err
723 where custom404Err = err404 { errBody = "myfile.txt just isn't there, please leave this server alone." }
710 where custom404Err = err404 { errBody = "myfile.txt just isn't there, please leave this server alone." }
726−Let's run this server (`dist/build/tutorial/tutorial 5`) and
713+Here's how that server looks in action:
727−query it, first without the file and then with the file.
730 $ curl --verbose http://localhost:8081/myfile.txt
716 $ curl --verbose http://localhost:8081/myfile.txt
@@ -773,10 +759,10 @@ Note that the type of `addHeader x` is different than the type of `x`!
774## Serving static files
760## Serving static files
776−*servant-server* also provides a way to just serve the content of a directory
762+**servant-server** also provides a way to just serve the content of a directory
777under some path in your web API. As mentioned earlier in this document, the
763under some path in your web API. As mentioned earlier in this document, the
778`Raw` combinator can be used in your APIs to mean "plug here any WAI
764`Raw` combinator can be used in your APIs to mean "plug here any WAI
779−application". Well, servant-server provides a function to get a file and
765+application". Well, **servant-server** provides a function to get a file and
780directory serving WAI application, namely:
766directory serving WAI application, namely:
782``` haskell ignore
768``` haskell ignore
@@ -784,136 +770,36 @@ directory serving WAI application, namely:
784serveDirectory :: FilePath -> Server Raw
770serveDirectory :: FilePath -> Server Raw
787−`serveDirectory`'s argument must be a path to a valid directory. You can see an
773+`serveDirectory`'s argument must be a path to a valid directory.
788−example below, runnable with `dist/build/tutorial/tutorial 6`
789−(you **must** run it from within the *servant-examples/* directory!), which is
790−a webserver that serves the various bits of code covered in this
793−The API type will be the following.
775+Here's an example API that will serve some static files:
795``` haskell
777``` haskell
796−type CodeAPI = "code" :> Raw
778+type StaticAPI = "static" :> Raw
799And the server:
781And the server:
801``` haskell
783``` haskell
802−codeAPI :: Proxy CodeAPI
784+staticAPI :: Proxy StaticAPI
803−codeAPI = Proxy
785+staticAPI = Proxy
806``` haskell
788``` haskell
807−server7 :: Server CodeAPI
789+server7 :: Server StaticAPI
808−server7 = serveDirectory "tutorial"
790+server7 = serveDirectory "static-files"
810app3 :: Application
792app3 :: Application
811−app3 = serve codeAPI EmptyConfig server7
793+app3 = serve staticAPI server7
814−This server will match any request whose path starts with `/code` and will look
796+This server will match any request whose path starts with `/static` and will look
815for a file at the path described by the rest of the request path, inside the
797for a file at the path described by the rest of the request path, inside the
816− *tutorial/* directory of the path you run the program from.
798+ *static-files/* directory of the path you run the program from.
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)
827−Here is our little server in action.
830−$ curl http://localhost:8081/code/T1.hs
831−{-# LANGUAGE DataKinds #-}
832−{-# LANGUAGE TypeFamilies #-}
833−{-# LANGUAGE DeriveGeneric #-}
834−{-# LANGUAGE TypeOperators #-}
837−import Data.Aeson
800+In other words: If a client requests `/static/foo.txt`, the server will look for a file at
838−import Data.Time.Calendar
801+`./static-files/foo.txt`. If that file exists it'll succeed and serve the file.
839−import GHC.Generics
802+If it doesn't exist, the handler will fail with a `404` status code.
847− , registration_date :: Day
848− } deriving (Eq, Show, Generic)
850−-- orphan ToJSON instance for Day. necessary to derive one for User
851−instance ToJSON Day where
852− -- display a day in YYYY-mm-dd format
853− toJSON d = toJSON (showGregorian d)
857−type UserAPI = "users" :> Get '[JSON] [User]
861− [ User "Isaac Newton" 372 "isaac@newton.co.uk" (fromGregorian 1683 3 1)
862− , User "Albert Einstein" 136 "ae@mc2.org" (fromGregorian 1905 12 1)
865−userAPI :: Proxy UserAPI
868−server :: Server UserAPI
869−server = return users
872−app = serve userAPI server
873−$ curl http://localhost:8081/code/tutorial.hs
875−import Network.Wai.Handler.Warp
876−import System.Environment
888−app :: String -> (Application -> IO ()) -> IO ()
898− "9" -> T9.writeJSFiles >> f T9.app
906− [n] -> app n (run 8081)
911− putStrLn "Usage:\t tutorial N"
912− putStrLn "\t\twhere N is the number of the example you want to run."
914−$ curl http://localhost:8081/foo
918## Nested APIs
804## Nested APIs
@@ -1123,7 +1009,7 @@ type Server api = ServerT api (ExceptT ServantErr IO)
1124`ServerT` is the actual type family that computes the required types for the
1010`ServerT` is the actual type family that computes the required types for the
1125handlers that's part of the `HasServer` class. It's like `Server` except that
1011handlers 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,
1012+it takes another parameter which is the monad you want your handlers to run in,
1127or more generally the return types of your handlers. This third parameter is
1013or more generally the return types of your handlers. This third parameter is
1128used for specifying the return type of the handler for an endpoint, e.g when
1014used for specifying the return type of the handler for an endpoint, e.g when
1129computing `ServerT (Get '[JSON] Person) SomeMonad`. The result would be
1015computing `ServerT (Get '[JSON] Person) SomeMonad`. The result would be
@@ -1131,7 +1017,7 @@ computing `ServerT (Get '[JSON] Person) SomeMonad`. The result would be
1132The first and main question one might have then is: how do we write handlers
1018The first and main question one might have then is: how do we write handlers
1133that run in another monad? How can we "bring back" the value from a given monad
1019that run in another monad? How can we "bring back" the value from a given monad
1134−into something *servant* can understand?
1020+into something **servant** can understand?
1136### Natural transformations
1022### Natural transformations
@@ -1140,11 +1026,15 @@ do we have?
1141``` haskell ignore
1027``` haskell ignore
1142newtype m :~> n = Nat { unNat :: forall a. m a -> n a}
1028newtype m :~> n = Nat { unNat :: forall a. m a -> n a}
1144−-- For example
1033+``` haskell
1145−-- listToMaybeNat ::`[] :~> Maybe`
1034+listToMaybeNat :: [] :~> Maybe
1146−-- listToMaybeNat = Nat listToMaybe -- from Data.Maybe
1035+listToMaybeNat = Nat listToMaybe -- from Data.Maybe
1148(`Nat` comes from "natural transformation", in case you're wondering.)
1038(`Nat` comes from "natural transformation", in case you're wondering.)
1150So if you want to write handlers using another monad/type than `ExceptT
1040So if you want to write handlers using another monad/type than `ExceptT
@@ -1152,20 +1042,20 @@ ServantErr IO`, say the `Reader String` monad, the first thing you have to
1152prepare is a function:
1042prepare is a function:
1154``` haskell ignore
1044``` haskell ignore
1155−readerToEither :: Reader String :~> ExceptT ServantErr IO
1045+readerToHandler :: Reader String :~> ExceptT ServantErr IO
1158−Let's start with `readerToEither'`. We obviously have to run the `Reader`
1048+Let's start with `readerToHandler'`. We obviously have to run the `Reader`
1159computation by supplying it with a `String`, like `"hi"`. We get an `a` out
1049computation by supplying it with a `String`, like `"hi"`. We get an `a` out
1160from that and can then just `return` it into `ExceptT`. We can then just wrap
1050from that and can then just `return` it into `ExceptT`. We can then just wrap
1161that function with the `Nat` constructor to make it have the fancier type.
1051that function with the `Nat` constructor to make it have the fancier type.
1163``` haskell
1053``` haskell
1164−readerToEither' :: forall a. Reader String a -> ExceptT ServantErr IO a
1054+readerToHandler' :: forall a. Reader String a -> ExceptT ServantErr IO a
1165−readerToEither' r = return (runReader r "hi")
1055+readerToHandler' r = return (runReader r "hi")
1167−readerToEither :: Reader String :~> ExceptT ServantErr IO
1057+readerToHandler :: Reader String :~> ExceptT ServantErr IO
1168−readerToEither = Nat readerToEither'
1058+readerToHandler = Nat readerToHandler'
1171We can write some simple webservice with the handlers running in `Reader String`.
1061We can write some simple webservice with the handlers running in `Reader String`.
@@ -1193,25 +1083,24 @@ ServantErr IO`. But there's a simple solution to this.
1194### Enter `enter`
1084### Enter `enter`
1196−That's right. We have just written `readerToEither`, which is exactly what we
1086+That's right. We have just written `readerToHandler`, which is exactly what we
1197−would need to apply to the results of all handlers to make the handlers have the
1087+would need to apply to all handlers to make the handlers have the
1198right type for `serve`. Being cumbersome to do by hand, we provide a function
1088right type for `serve`. Being cumbersome to do by hand, we provide a function
1199`enter` which takes a natural transformation between two parametrized types `m`
1089`enter` which takes a natural transformation between two parametrized types `m`
1200and `n` and a `ServerT someapi m`, and returns a `ServerT someapi n`.
1090and `n` and a `ServerT someapi m`, and returns a `ServerT someapi n`.
1202In our case, we can wrap up our little webservice by using `enter
1092In our case, we can wrap up our little webservice by using `enter
1203−readerToEither` on our handlers.
1093+readerToHandler` on our handlers.
1205``` haskell
1095``` haskell
1206readerServer :: Server ReaderAPI
1096readerServer :: Server ReaderAPI
1207−readerServer = enter readerToEither readerServerT
1097+readerServer = enter readerToHandler readerServerT
1209app4 :: Application
1099app4 :: Application
1210−app4 = serve readerAPI EmptyConfig readerServer
1100+app4 = serve readerAPI readerServer
1213−And we can indeed see this webservice in action by running
1103+This is the webservice in action:
1214−`dist/build/tutorial/tutorial 7`.
1217$ curl http://localhost:8081/a
1106$ curl http://localhost:8081/a
@@ -1222,7 +1111,6 @@ $ curl http://localhost:8081/b
1223## Conclusion
1112## Conclusion
1225−You're now equipped to write any kind of webservice/web-application using
1114+You're now equipped to write webservices/web-applications 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*.
1115+**servant**. The rest of this document focuses on **servant-client**,
1116+**servant-js** and **servant-docs**.