git.iko.soy/typeable/servant
on master help sign in
Tidy up tutorial
commitaa3716b6aac80e132af9fca3c6529ce2305b3835 authorDavid Turner <dave.c.turner@gmail.com> dateWed 17 May 2017, 05:50 (9 years ago) parenta3c5f17
5 files changed+35−15
doc/tutorial/ApiType.lhs+16−5 doc/tutorial/Client.lhs+13−2 doc/tutorial/Docs.lhs+3−4 doc/tutorial/Javascript.lhs−2 doc/tutorial/Server.lhs+3−2
doc/tutorial/ApiType.lhs+16−5
@@ -328,14 +328,25 @@ type ProtectedAPI11
328328
329329### Empty APIs
330330
331−TODO motivation...
331+Sometimes it is useful to be able to generalise an API over the type of some
332+part of it:
332333
333−``` haskell ignore
334−type UserAPI12
335− = UserAPI
336− :<|> EmptyAPI -- this adds nothing to the API
334+``` haskell
335+type UserAPI12 innerAPI
336+ = UserAPI -- this is the fixed bit of the API
337+ :<|> "inner" :> innerAPI -- this lets us put various other APIs under /inner
337338```
338339
340+If there is a case where you do not have anything extra to serve, you can use
341+the `EmptyAPI` combinator to indicate this:
342+
343+``` haskell
344+type UserAPI12Alone = UserAPI12 EmptyAPI
345+```
346+
347+This also works well as a placeholder for unfinished parts of an API while it
348+is under development.
349+
339350### Interoperability with `wai`: `Raw`
340351
341352Finally, we also include a combinator named `Raw` that provides an escape hatch
doc/tutorial/Client.lhs+13−2
@@ -62,7 +62,6 @@ Enough chitchat, let's see an example. Consider the following API type from the
6262type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
6363 :<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
6464 :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email
65− :<|> EmptyAPI
6665```
6766
6867What we are going to get with **servant-client** here is three functions, one to query each endpoint:
@@ -89,11 +88,23 @@ the function `client`. It takes one argument:
8988api :: Proxy API
9089api = Proxy
9190
92−position :<|> hello :<|> marketing :<|> EmptyClient = client api
91+position :<|> hello :<|> marketing = client api
9392```
9493
9594`client api` returns client functions for our _entire_ API, combined with `:<|>`, which we can pattern match on as above. You could say `client` "calculates" the correct type and number of client functions for the API type it is given (via a `Proxy`), as well as their implementations.
9695
96+If there is an `EmptyAPI` within your API, this matches the `EmptyClient`
97+constructor:
98+
99+``` haskell ignore
100+type API' = API :<|> EmptyAPI
101+
102+api' :: Proxy API'
103+api' = Proxy
104+
105+(position' :<|> hello' :<|> marketing') :<|> EmptyClient = client api'
106+```
107+
97108``` haskell ignore
98109-- | URI scheme to use
99110data Scheme =
doc/tutorial/Docs.lhs+3−4
@@ -38,10 +38,9 @@ Like client function generation, documentation generation amounts to inspecting
3838This time however, we have to assist **servant**. While it is able to deduce a lot of things about our API, it can't magically come up with descriptions of the various pieces of our APIs that are human-friendly and explain what's going on "at the business-logic level". A good example to study for documentation generation is our webservice with the `/position`, `/hello` and `/marketing` endpoints from earlier:
3939
4040``` haskell
41−type ExampleAPI = ("position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
41+type ExampleAPI = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
4242 :<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
43− :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email)
44− :<|> EmptyAPI
43+ :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email
4544
4645exampleAPI :: Proxy ExampleAPI
4746exampleAPI = Proxy
@@ -221,7 +220,7 @@ api :: Proxy DocsAPI
221220api = Proxy
222221
223222server :: Server DocsAPI
224−server = (Server.server3 :<|> emptyServer) :<|> Tagged serveDocs where
223+server = Server.server3 :<|> Tagged serveDocs where
225224 serveDocs _ respond =
226225 respond $ responseLBS ok200 [plain] docsBS
227226 plain = ("Content-Type", "text/plain")
doc/tutorial/Javascript.lhs−2
@@ -45,7 +45,6 @@ Now let's have the API type(s) and the accompanying datatypes.
4545``` haskell
4646type API = "point" :> Get '[JSON] Point
4747 :<|> "books" :> QueryParam "q" Text :> Get '[JSON] (Search Book)
48− :<|> EmptyAPI
4948
5049type API' = API :<|> Raw
5150
@@ -134,7 +133,6 @@ api' = Proxy
134133server :: Server API
135134server = randomPoint
136135 :<|> searchBook
137− :<|> emptyServer
138136
139137server' :: Server API'
140138server' = server
doc/tutorial/Server.lhs+3−2
@@ -1020,10 +1020,11 @@ serverFor = error "..."
10201020-- or the mailing list if you get stuck!
10211021```
10221022
1023−TODO prose
1023+If the API contains the `EmptyAPI` combinator, the corresponding server is
1024+called `emptyServer`:
10241025
10251026``` haskell
1026−type CombinedAPI2 = API :<|> EmptyAPI
1027+type CombinedAPI2 = API :<|> "empty" :> EmptyAPI
10271028
10281029server11 :: Server CombinedAPI2
10291030server11 = server3 :<|> emptyServer