on master help sign in
Merge pull request #7 from dlarsson/master

Support for matrix parameters

commitec3bebee69fe3ada4c107151463dd1736bad8766 authorJulian Arni <jkarni@gmail.com> dateTue 27 Jan 2015, 03:16 (12 years ago) parent44efc7fd603431
3 files changed+95−10
.gitignore+16−2 example/greet.hs+8−1 src/Servant/Docs.hs+71−7
.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
@@ -36,6 +36,13 @@ instance ToParam (QueryParam "capital" Bool) where
3636 "Get the greeting message in uppercase (true) or not (false). Default is false."
3737 Normal
3838
39+instance ToParam (MatrixParam "lang" String) where
40+ toParam _ =
41+ DocQueryParam "lang"
42+ ["en", "sv", "fr"]
43+ "Get the greeting message selected language. Default is en."
44+ Normal
45+
3946instance ToSample Greet where
4047 toSample = Just $ Greet "Hello, haskeller!"
4148
@@ -47,7 +54,7 @@ instance ToSample Greet where
4754-- API specification
4855type TestApi =
4956 -- GET /hello/:name?capital={true, false} returns a Greet as JSON
50− "hello" :> Capture "name" Text :> QueryParam "capital" Bool :> Get Greet
57+ "hello" :> MatrixParam "lang" String :> Capture "name" Text :> QueryParam "capital" Bool :> Get Greet
5158
5259 -- POST /greet with a Greet as JSON in the request body,
5360 -- returns a Greet as JSON
src/Servant/Docs.hs+71−7
@@ -216,6 +216,7 @@ data DocQueryParam = DocQueryParam
216216 , _paramKind :: ParamKind
217217 } deriving (Eq, Show)
218218
219+
219220-- | Type of GET parameter:
220221--
221222-- - Normal corresponds to @QueryParam@, i.e your usual GET parameter
@@ -265,11 +266,12 @@ defResponse = Response 200 []
265266-- You can tweak an 'Action' (like the default 'defAction') with these lenses
266267-- to transform an action and add some information to it.
267268data Action = Action
268− { _captures :: [DocCapture] -- type collected + user supplied info
269− , _headers :: [Text] -- type collected
270− , _params :: [DocQueryParam] -- type collected + user supplied info
271− , _rqbody :: Maybe ByteString -- user supplied
272− , _response :: Response -- user supplied
269+ { _captures :: [DocCapture] -- type collected + user supplied info
270+ , _headers :: [Text] -- type collected
271+ , _params :: [DocQueryParam] -- type collected + user supplied info
272+ , _mxParams :: [(String, [DocQueryParam])] -- type collected + user supplied info
273+ , _rqbody :: Maybe ByteString -- user supplied
274+ , _response :: Response -- user supplied
273275 } deriving (Eq, Show)
274276
275277-- Default 'Action'. Has no 'captures', no GET 'params', expects
@@ -278,12 +280,13 @@ data Action = Action
278280-- Tweakable with lenses.
279281--
280282-- > λ> defAction
281−-- > Action {_captures = [], _params = [], _rqbody = Nothing, _response = Response {_respStatus = 200, _respBody = Nothing}}
283+-- > Action {_captures = [], _headers = [], _params = [], _mxParams = [], _rqbody = Nothing, _response = Response {_respStatus = 200, _respBody = Nothing}}
282284-- > λ> defAction & response.respStatus .~ 201
283−-- > Action {_captures = [], _params = [], _rqbody = Nothing, _response = Response {_respStatus = 201, _respBody = Nothing}}
285+-- > Action {_captures = [], _headers = [], _params = [], _mxParams = [], _rqbody = Nothing, _response = Response {_respStatus = 201, _respBody = Nothing}}
284286defAction :: Action
285287defAction =
286288 Action []
289+ []
287290 []
288291 []
289292 Nothing
@@ -393,6 +396,7 @@ markdown = unlines . concat . map (uncurry printEndpoint) . HM.toList
393396 replicate len '-' :
394397 "" :
395398 capturesStr (action ^. captures) ++
399+ mxParamsStr (action ^. mxParams) ++
396400 headersStr (action ^. headers) ++
397401 paramsStr (action ^. params) ++
398402 rqbodyStr (action ^. rqbody) ++
@@ -413,6 +417,22 @@ markdown = unlines . concat . map (uncurry printEndpoint) . HM.toList
413417 captureStr cap =
414418 "- *" ++ (cap ^. capSymbol) ++ "*: " ++ (cap ^. capDesc)
415419
420+ mxParamsStr :: [(String, [DocQueryParam])] -> [String]
421+ mxParamsStr [] = []
422+ mxParamsStr l =
423+ "**Matrix Parameters**: " :
424+ "" :
425+ map segmentStr l ++
426+ "" :
427+ []
428+ segmentStr :: (String, [DocQueryParam]) -> String
429+ segmentStr (segment, l) = unlines $
430+ ("**" ++ segment ++ "**: ") :
431+ "" :
432+ map paramStr l ++
433+ "" :
434+ []
435+
416436 headersStr :: [Text] -> [String]
417437 headersStr [] = []
418438 headersStr l = [""] ++ map headerStr l ++ [""]
@@ -583,6 +603,50 @@ instance (KnownSymbol sym, ToParam (QueryFlag sym), HasDocs sublayout)
583603 paramP = Proxy :: Proxy (QueryFlag sym)
584604 action' = over params (|> toParam paramP) action
585605
606+
607+instance (KnownSymbol sym, ToParam (MatrixParam sym a), HasDocs sublayout)
608+ => HasDocs (MatrixParam sym a :> sublayout) where
609+
610+ docsFor Proxy (endpoint, action) =
611+ docsFor sublayoutP (endpoint', action')
612+
613+ where sublayoutP = Proxy :: Proxy sublayout
614+ paramP = Proxy :: Proxy (MatrixParam sym a)
615+ segment = endpoint ^. (path._last)
616+ segment' = action ^. (mxParams._last._1)
617+ endpoint' = over (path._last) (\p -> p ++ ";" ++ symbolVal symP ++ "=<value>") endpoint
618+
619+ action' = if segment' /= segment
620+ -- This is the first matrix parameter for this segment, insert a new entry into the mxParams list
621+ then over mxParams (|> (segment, [toParam paramP])) action
622+ -- We've already inserted a matrix parameter for this segment, append to the existing list
623+ else action & mxParams._last._2 <>~ [toParam paramP]
624+ symP = Proxy :: Proxy sym
625+
626+
627+instance (KnownSymbol sym, {- ToParam (MatrixParams sym a), -} HasDocs sublayout)
628+ => HasDocs (MatrixParams sym a :> sublayout) where
629+
630+ docsFor Proxy (endpoint, action) =
631+ docsFor sublayoutP (endpoint', action)
632+
633+ where sublayoutP = Proxy :: Proxy sublayout
634+ endpoint' = over path (\p -> p ++ [";" ++ symbolVal symP ++ "=<value>"]) endpoint
635+ symP = Proxy :: Proxy sym
636+
637+
638+instance (KnownSymbol sym, {- ToParam (MatrixFlag sym), -} HasDocs sublayout)
639+ => HasDocs (MatrixFlag sym :> sublayout) where
640+
641+ docsFor Proxy (endpoint, action) =
642+ docsFor sublayoutP (endpoint', action)
643+
644+ where sublayoutP = Proxy :: Proxy sublayout
645+
646+ endpoint' = over path (\p -> p ++ [";" ++ symbolVal symP]) endpoint
647+ symP = Proxy :: Proxy sym
648+
649+
586650instance HasDocs Raw where
587651 docsFor _proxy (endpoint, action) =
588652 single endpoint action