on master help sign in
Merge remote-tracking branch 'upstream/master' into wip-notes

Conflicts: src/Servant/Docs.hs

commitdd34ba0d92de5284262ed40624a88cc1055a15ee authorChristian Marie <christian@ponies.io> dateFri 30 Jan 2015, 15:57 (12 years ago) parentb85a90cec3bebe
4 files changed+121−28
.gitignore+16−2 example/greet.hs+8−1 example/greet.md+18−17 src/Servant/Docs.hs+79−8
.gitignore+16−2
@@ -1,3 +1,17 @@
1−.cabal-sandbox
2−cabal.sandbox.config
31dist
2+cabal-dev
3+*.o
4+*.hi
5+*.chi
6+*.chs.h
7+*.dyn_o
8+*.dyn_hi
9+.virtualenv
10+.hpc
11+.hsenv
12+.cabal-sandbox/
13+cabal.sandbox.config
14+cabal.config
15+*.prof
16+*.aux
17+*.hp
example/greet.hs+8−1
@@ -37,6 +37,13 @@ instance ToParam (QueryParam "capital" Bool) where
3737 \Default is false."
3838 Normal
3939
40+instance ToParam (MatrixParam "lang" String) where
41+ toParam _ =
42+ DocQueryParam "lang"
43+ ["en", "sv", "fr"]
44+ "Get the greeting message selected language. Default is en."
45+ Normal
46+
4047instance ToSample Greet where
4148 toSample = Just $ Greet "Hello, haskeller!"
4249
@@ -59,7 +66,7 @@ intro2 = DocIntro "This title is below the last"
5966-- API specification
6067type TestApi =
6168 -- GET /hello/:name?capital={true, false} returns a Greet as JSON
62− "hello" :> Capture "name" Text :> QueryParam "capital" Bool :> Get Greet
69+ "hello" :> MatrixParam "lang" String :> Capture "name" Text :> QueryParam "capital" Bool :> Get Greet
6370
6471 -- POST /greet with a Greet as JSON in the request body,
6572 -- returns a Greet as JSON
example/greet.md+18−17
@@ -13,9 +13,7 @@ You'll also note that multiple intros are possible.
1313#### Request Body:
1414
1515``` javascript
16−{
17− "msg": "Hello, haskeller!"
18−}
16+"Hello, haskeller!"
1917```
2018
2119#### Response:
@@ -24,30 +22,37 @@ You'll also note that multiple intros are possible.
2422 - If you use ?capital=true
2523
2624``` javascript
27−{
28− "msg": "HELLO, HASKELLER"
29−}
25+"HELLO, HASKELLER"
3026```
3127
3228 - If you use ?capital=false
3329
3430``` javascript
35−{
36− "msg": "Hello, haskeller"
37−}
31+"Hello, haskeller"
3832```
3933
40−## GET /hello/:name
34+## GET /hello;lang=<value>/:name
4135
4236#### Captures:
4337
4438- *name*: name of the person to greet
4539
40+#### Matrix Parameters**:
41+
42+**hello**:
43+
44+ - lang
45+ - **Values**: *en, sv, fr*
46+ - **Description**: Get the greeting message selected language. Default is en.
47+
48+
49+
50+
4651#### GET Parameters:
4752
4853 - capital
4954 - **Values**: *true, false*
50− - **Description**: Get the greeting message in uppercase (true) or not (false). Default is false.
55+ - **Description**: Get the greeting message in uppercase (true) or not (false).Default is false.
5156
5257
5358#### Response:
@@ -56,17 +61,13 @@ You'll also note that multiple intros are possible.
5661 - If you use ?capital=true
5762
5863``` javascript
59−{
60− "msg": "HELLO, HASKELLER"
61−}
64+"HELLO, HASKELLER"
6265```
6366
6467 - If you use ?capital=false
6568
6669``` javascript
67−{
68− "msg": "Hello, haskeller"
69−}
70+"Hello, haskeller"
7071```
7172
7273## DELETE /greet/:greetid
src/Servant/Docs.hs+79−8
@@ -73,6 +73,13 @@
7373-- > \Default is false."
7474-- > Normal
7575-- >
76+-- > instance ToParam (MatrixParam "lang" String) where
77+-- > toParam _ =
78+-- > DocQueryParam "lang"
79+-- > ["en", "sv", "fr"]
80+-- > "Get the greeting message selected language. Default is en."
81+-- > Normal
82+-- >
7683-- > instance ToSample Greet where
7784-- > toSample = Just $ Greet "Hello, haskeller!"
7885-- >
@@ -95,7 +102,7 @@
95102-- > -- API specification
96103-- > type TestApi =
97104-- > -- GET /hello/:name?capital={true, false} returns a Greet as JSON
98−-- > "hello" :> Capture "name" Text :> QueryParam "capital" Bool :> Get Greet
105+-- > "hello" :> MatrixParam "lang" String :> Capture "name" Text :> QueryParam "capital" Bool :> Get Greet
99106-- >
100107-- > -- POST /greet with a Greet as JSON in the request body,
101108-- > -- returns a Greet as JSON
@@ -116,6 +123,7 @@
116123-- > -- > docs testAPI
117124-- > docsGreet :: API
118125-- > docsGreet = docsWithIntros [intro1, intro2] testApi
126+-- >
119127-- > main :: IO ()
120128-- > main = putStrLn $ markdown docsGreet
121129module Servant.Docs
@@ -332,12 +340,13 @@ defResponse = Response 200 []
332340-- You can tweak an 'Action' (like the default 'defAction') with these lenses
333341-- to transform an action and add some information to it.
334342data Action = Action
335− { _captures :: [DocCapture] -- type collected + user supplied info
336− , _headers :: [Text] -- type collected
337− , _params :: [DocQueryParam] -- type collected + user supplied info
343+ { _captures :: [DocCapture] -- type collected + user supplied info
344+ , _headers :: [Text] -- type collected
345+ , _params :: [DocQueryParam] -- type collected + user supplied info
338346 , _notes :: [DocNote] -- user supplied
339− , _rqbody :: Maybe ByteString -- user supplied
340− , _response :: Response -- user supplied
347+ , _mxParams :: [(String, [DocQueryParam])] -- type collected + user supplied info
348+ , _rqbody :: Maybe ByteString -- user supplied
349+ , _response :: Response -- user supplied
341350 } deriving (Eq, Show)
342351
343352-- Default 'Action'. Has no 'captures', no GET 'params', expects
@@ -346,15 +355,16 @@ data Action = Action
346355-- Tweakable with lenses.
347356--
348357-- > λ> defAction
349−-- > Action {_captures = [], _params = [], _rqbody = Nothing, _response = Response {_respStatus = 200, _respBody = Nothing}}
358+-- > Action {_captures = [], _headers = [], _params = [], _mxParams = [], _rqbody = Nothing, _response = Response {_respStatus = 200, _respBody = Nothing}}
350359-- > λ> defAction & response.respStatus .~ 201
351−-- > Action {_captures = [], _params = [], _rqbody = Nothing, _response = Response {_respStatus = 201, _respBody = Nothing}}
360+-- > Action {_captures = [], _headers = [], _params = [], _mxParams = [], _rqbody = Nothing, _response = Response {_respStatus = 201, _respBody = Nothing}}
352361defAction :: Action
353362defAction =
354363 Action []
355364 []
356365 []
357366 []
367+ []
358368 Nothing
359369 defResponse
360370
@@ -473,6 +483,7 @@ markdown api = unlines $
473483 "" :
474484 notesStr (action ^. notes) ++
475485 capturesStr (action ^. captures) ++
486+ mxParamsStr (action ^. mxParams) ++
476487 headersStr (action ^. headers) ++
477488 paramsStr (action ^. params) ++
478489 rqbodyStr (action ^. rqbody) ++
@@ -515,6 +526,22 @@ markdown api = unlines $
515526 captureStr cap =
516527 "- *" ++ (cap ^. capSymbol) ++ "*: " ++ (cap ^. capDesc)
517528
529+ mxParamsStr :: [(String, [DocQueryParam])] -> [String]
530+ mxParamsStr [] = []
531+ mxParamsStr l =
532+ "#### Matrix Parameters:" :
533+ "" :
534+ map segmentStr l ++
535+ "" :
536+ []
537+ segmentStr :: (String, [DocQueryParam]) -> String
538+ segmentStr (segment, l) = unlines $
539+ ("**" ++ segment ++ "**:") :
540+ "" :
541+ map paramStr l ++
542+ "" :
543+ []
544+
518545 headersStr :: [Text] -> [String]
519546 headersStr [] = []
520547 headersStr l = [""] ++ map headerStr l ++ [""]
@@ -685,6 +712,50 @@ instance (KnownSymbol sym, ToParam (QueryFlag sym), HasDocs sublayout)
685712 paramP = Proxy :: Proxy (QueryFlag sym)
686713 action' = over params (|> toParam paramP) action
687714
715+
716+instance (KnownSymbol sym, ToParam (MatrixParam sym a), HasDocs sublayout)
717+ => HasDocs (MatrixParam sym a :> sublayout) where
718+
719+ docsFor Proxy (endpoint, action) =
720+ docsFor sublayoutP (endpoint', action')
721+
722+ where sublayoutP = Proxy :: Proxy sublayout
723+ paramP = Proxy :: Proxy (MatrixParam sym a)
724+ segment = endpoint ^. (path._last)
725+ segment' = action ^. (mxParams._last._1)
726+ endpoint' = over (path._last) (\p -> p ++ ";" ++ symbolVal symP ++ "=<value>") endpoint
727+
728+ action' = if segment' /= segment
729+ -- This is the first matrix parameter for this segment, insert a new entry into the mxParams list
730+ then over mxParams (|> (segment, [toParam paramP])) action
731+ -- We've already inserted a matrix parameter for this segment, append to the existing list
732+ else action & mxParams._last._2 <>~ [toParam paramP]
733+ symP = Proxy :: Proxy sym
734+
735+
736+instance (KnownSymbol sym, {- ToParam (MatrixParams sym a), -} HasDocs sublayout)
737+ => HasDocs (MatrixParams sym a :> sublayout) where
738+
739+ docsFor Proxy (endpoint, action) =
740+ docsFor sublayoutP (endpoint', action)
741+
742+ where sublayoutP = Proxy :: Proxy sublayout
743+ endpoint' = over path (\p -> p ++ [";" ++ symbolVal symP ++ "=<value>"]) endpoint
744+ symP = Proxy :: Proxy sym
745+
746+
747+instance (KnownSymbol sym, {- ToParam (MatrixFlag sym), -} HasDocs sublayout)
748+ => HasDocs (MatrixFlag sym :> sublayout) where
749+
750+ docsFor Proxy (endpoint, action) =
751+ docsFor sublayoutP (endpoint', action)
752+
753+ where sublayoutP = Proxy :: Proxy sublayout
754+
755+ endpoint' = over path (\p -> p ++ [";" ++ symbolVal symP]) endpoint
756+ symP = Proxy :: Proxy sym
757+
758+
688759instance HasDocs Raw where
689760 docsFor _proxy (endpoint, action) =
690761 single endpoint action