@@ -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