on master help sign in
Tidy up tutorial
aa3716bDavid Turner
doc/tutorial/ApiType.lhs+16−5
@@ -328,14 +328,25 @@ type ProtectedAPI11
328
328
329### Empty APIs
329### Empty APIs
330
330
331−TODO motivation...
331+Sometimes it is useful to be able to generalise an API over the type of some
332+part of it:
332
333
333−``` haskell ignore
334+``` haskell
334−type UserAPI12
335+type UserAPI12 innerAPI
335− = UserAPI
336+ = UserAPI -- this is the fixed bit of the API
336− :<|> EmptyAPI -- this adds nothing to the API
337+ :<|> "inner" :> innerAPI -- this lets us put various other APIs under /inner
337```
338```
338
339
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+
339### Interoperability with `wai`: `Raw`
350### Interoperability with `wai`: `Raw`
340
351
341Finally, we also include a combinator named `Raw` that provides an escape hatch
352Finally, 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
62type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
62type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
63 :<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
63 :<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
64 :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email
64 :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email
65− :<|> EmptyAPI
66```
65```
67
66
68What we are going to get with **servant-client** here is three functions, one to query each endpoint:
67What 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:
89api :: Proxy API
88api :: Proxy API
90api = Proxy
89api = Proxy
91
90
92−position :<|> hello :<|> marketing :<|> EmptyClient = client api
91+position :<|> hello :<|> marketing = client api
93```
92```
94
93
95`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.
94`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.
96
95
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+
97``` haskell ignore
108``` haskell ignore
98-- | URI scheme to use
109-- | URI scheme to use
99data Scheme =
110data Scheme =
doc/tutorial/Docs.lhs+3−4
@@ -38,10 +38,9 @@ Like client function generation, documentation generation amounts to inspecting
38This 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:
38This 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:
39
39
40``` haskell
40``` 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
42 :<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
42 :<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
43− :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email)
43+ :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email
44− :<|> EmptyAPI
45
44
46exampleAPI :: Proxy ExampleAPI
45exampleAPI :: Proxy ExampleAPI
47exampleAPI = Proxy
46exampleAPI = Proxy
@@ -221,7 +220,7 @@ api :: Proxy DocsAPI
221api = Proxy
220api = Proxy
222
221
223server :: Server DocsAPI
222server :: Server DocsAPI
224−server = (Server.server3 :<|> emptyServer) :<|> Tagged serveDocs where
223+server = Server.server3 :<|> Tagged serveDocs where
225 serveDocs _ respond =
224 serveDocs _ respond =
226 respond $ responseLBS ok200 [plain] docsBS
225 respond $ responseLBS ok200 [plain] docsBS
227 plain = ("Content-Type", "text/plain")
226 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.
45``` haskell
45``` haskell
46type API = "point" :> Get '[JSON] Point
46type API = "point" :> Get '[JSON] Point
47 :<|> "books" :> QueryParam "q" Text :> Get '[JSON] (Search Book)
47 :<|> "books" :> QueryParam "q" Text :> Get '[JSON] (Search Book)
48− :<|> EmptyAPI
49
48
50type API' = API :<|> Raw
49type API' = API :<|> Raw
51
50
@@ -134,7 +133,6 @@ api' = Proxy
134server :: Server API
133server :: Server API
135server = randomPoint
134server = randomPoint
136 :<|> searchBook
135 :<|> searchBook
137− :<|> emptyServer
138
136
139server' :: Server API'
137server' :: Server API'
140server' = server
138server' = server
doc/tutorial/Server.lhs+3−2
@@ -1020,10 +1020,11 @@ serverFor = error "..."
1020-- or the mailing list if you get stuck!
1020-- or the mailing list if you get stuck!
1021```
1021```
1022
1022
1023−TODO prose
1023+If the API contains the `EmptyAPI` combinator, the corresponding server is
1024+called `emptyServer`:
1024
1025
1025``` haskell
1026``` haskell
1026−type CombinedAPI2 = API :<|> EmptyAPI
1027+type CombinedAPI2 = API :<|> "empty" :> EmptyAPI
1027
1028
1028server11 :: Server CombinedAPI2
1029server11 :: Server CombinedAPI2
1029server11 = server3 :<|> emptyServer
1030server11 = server3 :<|> emptyServer