git.iko.soy/typeable/servant
on master help sign in
tutorial: read through Server.lhs
commite84fea334a10c27c38d14d17525d00e7eb8bb429 authorSönke Hahn <soenkehahn@gmail.com> dateSat 27 Feb 2016, 19:53 (11 years ago) parente68cf28
3 files changed+108−220
doc/tutorial/Docs.lhs+1−1 doc/tutorial/Javascript.lhs+1−1 doc/tutorial/Server.lhs+106−218
doc/tutorial/Docs.lhs+1−1
@@ -228,7 +228,7 @@ server = Server.server3 :<|> serveDocs
228228 plain = ("Content-Type", "text/plain")
229229
230230app :: Application
231−app = serve api EmptyConfig server
231+app = serve api server
232232```
233233
234234And 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.
doc/tutorial/Javascript.lhs+1−1
@@ -134,7 +134,7 @@ server' = server
134134 :<|> serveDirectory "tutorial/t9"
135135
136136app :: Application
137−app = serve api' EmptyConfig server'
137+app = serve api' server'
138138```
139139
140140Why 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.
doc/tutorial/Server.lhs+106−218
@@ -5,7 +5,7 @@ type. Can we have a webservice already?
55
66## A first example
77
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
99write our first webservice.
1010
1111The source for this tutorial section is a literate haskell file, so first we
@@ -26,7 +26,7 @@ module Server where
2626import Prelude ()
2727import Prelude.Compat
2828
29−import Control.Monad.IO.Class
29+import Control.Monad.Except
3030import Control.Monad.Reader
3131import Control.Monad.Trans.Except
3232import Data.Aeson.Compat
@@ -34,6 +34,7 @@ import Data.Aeson.Types
3434import Data.Attoparsec.ByteString
3535import Data.ByteString (ByteString)
3636import Data.List
37+import Data.Maybe
3738import Data.String.Conversions
3839import Data.Time.Calendar
3940import GHC.Generics
@@ -49,16 +50,12 @@ import qualified Data.Aeson.Parser
4950import qualified Text.Blaze.Html
5051```
5152
52−``` haskell ignore
53−{-# LANGUAGE TypeFamilies #-}
54−```
55−
56−**Important**: the `Servant` module comes from the *servant-server* package,
53+**Important**: the `Servant` module comes from the **servant-server** package,
5754the 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
5956types as well as everything you need to turn your request handlers into a
6057fully-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
6259else.
6360
6461We will write a server that will serve the following API.
@@ -154,9 +151,8 @@ main = run 8081 app1
154151
155152You can put this all into a file or just grab [servant's
156153repo](http://github.com/haskell-servant/servant) and look at the
157−*servant-examples* directory. The code we have just explored is in
158−*tutorial/T1.hs*, runnable with
159−`dist/build/tutorial/tutorial 1`.
154+*doc/tutorial* directory. This code (the source of this web page) is in
155+*doc/tutorial/Server.lhs*.
160156
161157If you run it, you can go to `http://localhost:8081/users` in your browser or
162158query it with curl and you see:
@@ -192,7 +188,7 @@ users2 = [isaac, albert]
192188
193189Now, just like we separate the various endpoints in `UserAPI` with `:<|>`, we
194190are 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.
196192
197193``` haskell
198194server2 :: Server UserAPI2
@@ -201,9 +197,8 @@ server2 = return users2
201197 :<|> return isaac
202198```
203199
204−And that's it! You can run this example with
205−`dist/build/tutorial/tutorial 2` and check out the data available
206−at `/users`, `/albert` and `/isaac`.
200+And that's it! You can run this example in the same way that we showed for
201+`server1` and check out the data available at `/users`, `/albert` and `/isaac`.
207202
208203## From combinators to handler arguments
209204
@@ -298,8 +293,7 @@ parameter might not always be there);
298293
299294 - a `ReqBody contentTypeList a` becomes an argument of type `a`;
300295
301−And that's it. You can see this example in action by running
302−`dist/build/tutorial/tutorial 3`.
296+And that's it. Here's the example in action:
303297
304298``` bash
305299$ curl http://localhost:8081/position/1/2
@@ -312,19 +306,18 @@ $ curl -X POST -d '{"name":"Alp Mestanogullari", "email" : "alp@foo.com", "age":
312306{"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"}
313307```
314308
315−For reference, here's a list of some combinators from *servant* and for those
316−that get turned into arguments to the handlers, the type of the argument.
309+For reference, here's a list of some combinators from **servant**:
317310
318311 > - `Delete`, `Get`, `Patch`, `Post`, `Put`: these do not become arguments. They provide the return type of handlers, which usually is `ExceptT ServantErr IO <something>`.
319312 > - `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.
321− > - `QueryFlag "something"` and `MatrixFlag "something"` get turned into arguments of type `Bool`.
322− > - `QueryParams "something" a` and `MatrixParams "something" a` get turned into arguments of type `[a]`.
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.
314+ > - `QueryFlag "something"` gets turned into an argument of type `Bool`.
315+ > - `QueryParams "something" a` gets turned into an argument of type `[a]`.
323316 > - `ReqBody contentTypes a` gets turned into an argument of type `a`.
324317
325318## The `FromHttpApiData`/`ToHttpApiData` classes
326319
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
328321to decode a `ClientInfo` value from the request body? This is what this and the
329322following two sections address.
330323
@@ -333,7 +326,7 @@ following two sections address.
333326corresponding (textual) value in the request's "metadata". How types are
334327decoded from headers, captures, and query params is expressed in a class
335328`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)):
337330
338331``` haskell ignore
339332class FromHttpApiData a where
@@ -355,15 +348,15 @@ As you can see, as long as you provide either `parseUrlPiece` (for `Capture`s)
355348or `parseQueryParam` (for `QueryParam`s), the other methods will be defined in
356349terms of this.
357350
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
359352ones, and wonderful documentation.
360353
361354There's not much else to say about these classes. You will need instances for
362355them when using `Capture`, `QueryParam`, `QueryParams`, and `Header` with your
363356types. You will need `FromHttpApiData` instances for server-side request
364357handlers and `ToHttpApiData` instances only when using
365−*servant-client*, as described in the [section about deriving haskell
366−functions to query an API](/tutorial/client.html).
358+**servant-client**, as described in the [section about deriving haskell
359+functions to query an API](Client.html).
367360
368361## Using content-types with your data types
369362
@@ -371,14 +364,15 @@ The same principle was operating when decoding request bodies from JSON, and
371364responses *into* JSON. (JSON is just the running example - you can do this with
372365any content-type.)
373366
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
375368all of this work.
376369
377370### The truth behind `JSON`
378371
379372
380−What exactly is `JSON`? Like the 3 other content types provided out of the box
381−by *servant*, it's a really dumb data type.
373+What exactly is `JSON` (the type as used in `Get '[JSON] User`)? Like the 3
374+other content-types provided out of the box by **servant**, it's a really dumb
375+data type.
382376
383377``` haskell ignore
384378data JSON
@@ -388,14 +382,15 @@ data OctetStream
388382```
389383
390384Obviously, 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
392386a special *symbol* that's associated with encoding (resp. decoding) to (resp.
393387from) the *JSON* format. The way this association is performed can be
394388decomposed into two steps.
395389
396390The first step is to provide a proper
397−[`MediaType`](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
391+`MediaType` (from
392+[**http-media**](https://hackage.haskell.org/package/http-media-0.6.2/docs/Network-HTTP-Media.html))
393+representation for `JSON`, or for your own content-types. If you look at the
399394haddocks from this link, you can see that we just have to specify
400395`application/json` using the appropriate functions. In our case, we can just
401396use `(//) :: ByteString -> ByteString -> MediaType`. The precise way to specify
@@ -411,14 +406,14 @@ instance Accept JSON where
411406```
412407
413408The second step is centered around the `MimeRender` and `MimeUnrender` classes.
414−These classes just let you specify a way to respectively encode and decode
415−values respectively into or from your content-type's representation.
409+These classes just let you specify a way to encode and decode
410+values into or from your content-type's representation.
416411
417412``` haskell ignore
418413class Accept ctype => MimeRender ctype a where
419− mimeRender :: Proxy ctype -> a -> ByteString
414+ mimeRender :: Proxy ctype -> a -> ByteString
420415 -- alternatively readable as:
421− mimeRender :: Proxy ctype -> (a -> ByteString)
416+ mimeRender :: Proxy ctype -> (a -> ByteString)
422417```
423418
424419Given a content-type and some user type, `MimeRender` provides a function that
@@ -444,7 +439,7 @@ class Accept ctype => MimeUnrender ctype a where
444439We don't have much work to do there either, `Data.Aeson.eitherDecode` is
445440precisely what we need. However, it only allows arrays and objects as toplevel
446441JSON 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
448443JSON value at the toplevel of a "JSON document". Here's the definition in case
449444you are curious.
450445
@@ -462,20 +457,20 @@ instance FromJSON a => MimeUnrender JSON a where
462457 mimeUnrender _ = eitherDecodeLenient
463458```
464459
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`,
466461`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
468463HTML representation of the data they want, ready to be included in any HTML
469464document, e.g. using [jQuery's `load` function](https://api.jquery.com/load/),
470465simply by adding `Accept: text/html` to their request headers.
471466
472−### Case-studies: *servant-blaze* and *servant-lucid*
467+### Case-studies: **servant-blaze** and **servant-lucid**
473468
474469These 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)
476−or [lucid](http://hackage.haskell.org/package/lucid). The best option for
477−*servant* is obviously to support both (and hopefully other templating
478−solutions!).
470+Haskell use either [**blaze-html**](http://hackage.haskell.org/package/blaze-html)
471+or [**lucid**](http://hackage.haskell.org/package/lucid). The best option for
472+**servant** is obviously to support both (and hopefully other templating
473+solutions!). We're first going to look at **lucid**:
479474
480475``` haskell
481476data HTMLLucid
@@ -483,24 +478,20 @@ data HTMLLucid
483478
484479Once again, the data type is just there as a symbol for the encoding/decoding
485480functions, 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.
487−
488−Both packages also have the same `Accept` instance for their `HTMLLucid` type.
481+**lucid** doesn't provide a way to extract data from HTML.
489482
490483``` haskell
491484instance Accept HTMLLucid where
492485 contentType _ = "text" // "html" /: ("charset", "utf-8")
493486```
494487
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
496489us specify additional information about a content-type, like the charset here.
497490
498−The rendering instances for both packages both call similar functions that take
491+The rendering instances call similar functions that take
499492types with an appropriate instance to an "abstract" HTML representation and
500493then write that to a `ByteString`.
501494
502−For *lucid*:
503−
504495``` haskell
505496instance ToHtml a => MimeRender HTMLLucid a where
506497 mimeRender _ = renderBS . toHtml
@@ -511,7 +502,7 @@ instance MimeRender HTMLLucid (Html a) where
511502 mimeRender _ = renderBS
512503```
513504
514−For *blaze-html*:
505+For **blaze-html** everything works very similarly:
515506
516507``` haskell
517508-- For this tutorial to compile 'HTMLLucid' and 'HTMLBlaze' have to be
@@ -531,15 +522,13 @@ instance MimeRender HTMLBlaze Text.Blaze.Html.Html where
531522 mimeRender _ = renderHtml
532523```
533524
534−Both [servant-blaze](http://hackage.haskell.org/package/servant-blaze) and
535−[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
537−appropriate class (`ToMarkup` for *blaze-html*, `ToHtml` for *lucid*).
538−
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.
525+Both [**servant-blaze**](http://hackage.haskell.org/package/servant-blaze) and
526+[**servant-lucid**](http://hackage.haskell.org/package/servant-lucid) let you use
527+`HTMLLucid` and `HTMLBlaze` in any content-type list as long as you provide an instance of the
528+appropriate class (`ToMarkup` for **blaze-html**, `ToHtml` for **lucid**).
541529
542−We will be serving the following API:
530+We can now write a webservice that uses **servant-lucid** to show the `HTMLLucid`
531+content-type in action. We will be serving the following API:
543532
544533``` haskell
545534type PersonAPI = "persons" :> Get '[JSON, HTMLLucid] [Person]
@@ -556,7 +545,7 @@ data Person = Person
556545instance ToJSON Person
557546```
558547
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
560549a list of `Person`s as a table with a row per person.
561550
562551``` haskell
@@ -600,10 +589,10 @@ server4 :: Server PersonAPI
600589server4 = return people
601590
602591app2 :: Application
603−app2 = serve personAPI EmptyConfig server4
592+app2 = serve personAPI server4
604593```
605594
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:
607596
608597``` bash
609598 $ 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
616605## The `ExceptT ServantErr IO` monad
617606
618607At the heart of the handlers is the monad they run in, namely `ExceptT
619−ServantErr IO`. One might wonder: why this monad? The answer is that it is the
608+ServantErr IO`
609+([haddock documentation for `ExceptT`](http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#t:ExceptT)).
610+One might wonder: why this monad? The answer is that it is the
620611simplest monad with the following properties:
621612
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`);
613+- it lets us both return a successful result (using `return`)
614+or "fail" with a descriptive error (using `throwError`);
625615- 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`.
627617
628618Let's recall some definitions.
629619
630620``` haskell ignore
631−-- from the Prelude
632−data Either e a = Left e | Right a
633−
634621-- 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))
636623```
637624
638625In 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.
654641Another important instance from the list above is `MonadIO m => MonadIO
655642(ExceptT e m)`.
656643[`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:
658645
659646``` haskell ignore
660647class Monad m => MonadIO m where
661648 liftIO :: IO a -> m a
662649```
663650
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
665652`e`, `ExceptT e IO` has a `MonadIO` instance. So if you want to run any kind of
666653IO computation in your handlers, just use `liftIO`:
667654
@@ -684,7 +671,7 @@ server5 = do
684671
685672If you want to explicitly fail at providing the result promised by an endpoint
686673using 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
688675and provide it with the appropriate value of type `ServantErr`, which is
689676defined as:
690677
@@ -703,7 +690,7 @@ use record update syntax:
703690
704691``` haskell
705692failingHandler :: ExceptT ServantErr IO ()
706−failingHandler = throwE myerr
693+failingHandler = throwError myerr
707694
708695 where myerr :: ServantErr
709696 myerr = err503 { errBody = "Sorry dear user." }
@@ -718,13 +705,12 @@ server6 = do
718705 exists <- liftIO (doesFileExist "myfile.txt")
719706 if exists
720707 then liftIO (readFile "myfile.txt") >>= return . FileContent
721− else throwE custom404Err
708+ else throwError custom404Err
722709
723710 where custom404Err = err404 { errBody = "myfile.txt just isn't there, please leave this server alone." }
724711```
725712
726−Let's run this server (`dist/build/tutorial/tutorial 5`) and
727−query it, first without the file and then with the file.
713+Here's how that server looks in action:
728714
729715``` bash
730716 $ 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`!
773759
774760## Serving static files
775761
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
777763under some path in your web API. As mentioned earlier in this document, the
778764`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
780766directory serving WAI application, namely:
781767
782768``` haskell ignore
@@ -784,136 +770,36 @@ directory serving WAI application, namely:
784770serveDirectory :: FilePath -> Server Raw
785771```
786772
787−`serveDirectory`'s argument must be a path to a valid directory. You can see an
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
791−getting-started.
773+`serveDirectory`'s argument must be a path to a valid directory.
792774
793−The API type will be the following.
775+Here's an example API that will serve some static files:
794776
795777``` haskell
796−type CodeAPI = "code" :> Raw
778+type StaticAPI = "static" :> Raw
797779```
798780
799781And the server:
800782
801783``` haskell
802−codeAPI :: Proxy CodeAPI
803−codeAPI = Proxy
784+staticAPI :: Proxy StaticAPI
785+staticAPI = Proxy
804786```
805787
806788``` haskell
807−server7 :: Server CodeAPI
808−server7 = serveDirectory "tutorial"
789+server7 :: Server StaticAPI
790+server7 = serveDirectory "static-files"
809791
810792app3 :: Application
811−app3 = serve codeAPI EmptyConfig server7
793+app3 = serve staticAPI server7
812794```
813795
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
815797for 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.
817−
818−In other words:
819−
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)
826−
827−Here is our little server in action.
828−
829−``` haskell ignore
830−$ curl http://localhost:8081/code/T1.hs
831−{-# LANGUAGE DataKinds #-}
832−{-# LANGUAGE TypeFamilies #-}
833−{-# LANGUAGE DeriveGeneric #-}
834−{-# LANGUAGE TypeOperators #-}
835−module T1 where
798+ *static-files/* directory of the path you run the program from.
836799
837−import Data.Aeson
838−import Data.Time.Calendar
839−import GHC.Generics
840−import Network.Wai
841−import Servant
842−
843−data User = User
844− { name :: String
845− , age :: Int
846− , email :: String
847− , registration_date :: Day
848− } deriving (Eq, Show, Generic)
849−
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)
854−
855−instance ToJSON User
856−
857−type UserAPI = "users" :> Get '[JSON] [User]
858−
859−users :: [User]
860−users =
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)
863− ]
864−
865−userAPI :: Proxy UserAPI
866−userAPI = Proxy
867−
868−server :: Server UserAPI
869−server = return users
870−
871−app :: Application
872−app = serve userAPI server
873−$ curl http://localhost:8081/code/tutorial.hs
874−import Network.Wai
875−import Network.Wai.Handler.Warp
876−import System.Environment
877−
878−import qualified T1
879−import qualified T2
880−import qualified T3
881−import qualified T4
882−import qualified T5
883−import qualified T6
884−import qualified T7
885−import qualified T9
886−import qualified T10
887−
888−app :: String -> (Application -> IO ()) -> IO ()
889−app n f = case n of
890− "1" -> f T1.app
891− "2" -> f T2.app
892− "3" -> f T3.app
893− "4" -> f T4.app
894− "5" -> f T5.app
895− "6" -> f T6.app
896− "7" -> f T7.app
897− "8" -> f T3.app
898− "9" -> T9.writeJSFiles >> f T9.app
899− "10" -> f T10.app
900− _ -> usage
901−
902−main :: IO ()
903−main = do
904− args <- getArgs
905− case args of
906− [n] -> app n (run 8081)
907− _ -> usage
908−
909−usage :: IO ()
910−usage = do
911− putStrLn "Usage:\t tutorial N"
912− putStrLn "\t\twhere N is the number of the example you want to run."
913−
914−$ curl http://localhost:8081/foo
915−not found
916−```
800+In other words: If a client requests `/static/foo.txt`, the server will look for a file at
801+`./static-files/foo.txt`. If that file exists it'll succeed and serve the file.
802+If it doesn't exist, the handler will fail with a `404` status code.
917803
918804## Nested APIs
919805
@@ -1123,7 +1009,7 @@ type Server api = ServerT api (ExceptT ServantErr IO)
11231009
11241010`ServerT` is the actual type family that computes the required types for the
11251011handlers 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,
11271013or more generally the return types of your handlers. This third parameter is
11281014used for specifying the return type of the handler for an endpoint, e.g when
11291015computing `ServerT (Get '[JSON] Person) SomeMonad`. The result would be
@@ -1131,7 +1017,7 @@ computing `ServerT (Get '[JSON] Person) SomeMonad`. The result would be
11311017
11321018The first and main question one might have then is: how do we write handlers
11331019that 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?
11351021
11361022### Natural transformations
11371023
@@ -1140,11 +1026,15 @@ do we have?
11401026
11411027``` haskell ignore
11421028newtype m :~> n = Nat { unNat :: forall a. m a -> n a}
1029+```
1030+
1031+For example:
11431032
1144−-- For example
1145−-- listToMaybeNat ::`[] :~> Maybe`
1146−-- listToMaybeNat = Nat listToMaybe -- from Data.Maybe
1033+``` haskell
1034+listToMaybeNat :: [] :~> Maybe
1035+listToMaybeNat = Nat listToMaybe -- from Data.Maybe
11471036```
1037+
11481038(`Nat` comes from "natural transformation", in case you're wondering.)
11491039
11501040So 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
11521042prepare is a function:
11531043
11541044``` haskell ignore
1155−readerToEither :: Reader String :~> ExceptT ServantErr IO
1045+readerToHandler :: Reader String :~> ExceptT ServantErr IO
11561046```
11571047
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`
11591049computation by supplying it with a `String`, like `"hi"`. We get an `a` out
11601050from that and can then just `return` it into `ExceptT`. We can then just wrap
11611051that function with the `Nat` constructor to make it have the fancier type.
11621052
11631053``` haskell
1164−readerToEither' :: forall a. Reader String a -> ExceptT ServantErr IO a
1165−readerToEither' r = return (runReader r "hi")
1054+readerToHandler' :: forall a. Reader String a -> ExceptT ServantErr IO a
1055+readerToHandler' r = return (runReader r "hi")
11661056
1167−readerToEither :: Reader String :~> ExceptT ServantErr IO
1168−readerToEither = Nat readerToEither'
1057+readerToHandler :: Reader String :~> ExceptT ServantErr IO
1058+readerToHandler = Nat readerToHandler'
11691059```
11701060
11711061We 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.
11931083
11941084### Enter `enter`
11951085
1196−That's right. We have just written `readerToEither`, which is exactly what we
1197−would need to apply to the results of all handlers to make the handlers have the
1086+That's right. We have just written `readerToHandler`, which is exactly what we
1087+would need to apply to all handlers to make the handlers have the
11981088right type for `serve`. Being cumbersome to do by hand, we provide a function
11991089`enter` which takes a natural transformation between two parametrized types `m`
12001090and `n` and a `ServerT someapi m`, and returns a `ServerT someapi n`.
12011091
12021092In our case, we can wrap up our little webservice by using `enter
1203−readerToEither` on our handlers.
1093+readerToHandler` on our handlers.
12041094
12051095``` haskell
12061096readerServer :: Server ReaderAPI
1207−readerServer = enter readerToEither readerServerT
1097+readerServer = enter readerToHandler readerServerT
12081098
12091099app4 :: Application
1210−app4 = serve readerAPI EmptyConfig readerServer
1100+app4 = serve readerAPI readerServer
12111101```
12121102
1213−And we can indeed see this webservice in action by running
1214−`dist/build/tutorial/tutorial 7`.
1103+This is the webservice in action:
12151104
12161105``` bash
12171106$ curl http://localhost:8081/a
@@ -1222,7 +1111,6 @@ $ curl http://localhost:8081/b
12221111
12231112## Conclusion
12241113
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*.
1114+You're now equipped to write webservices/web-applications using
1115+**servant**. The rest of this document focuses on **servant-client**,
1116+**servant-js** and **servant-docs**.