git.iko.soy/typeable/servant
on master help sign in
Improve documentation.

I also slipped a change into the Matrix Paramters section markdown generation, there is one less (superfluous) newline there now.

commitb935f2818513e82725f3402dc14967e118d4a8d9 authorChristian Marie <christian@ponies.io> dateWed 18 Feb 2015, 12:49 (12 years ago) parenta008e08
3 files changed+80−26
example/greet.hs+13−5 example/greet.md+13−3 src/Servant/Docs.hs+54−18
example/greet.hs+13−5
@@ -52,6 +52,11 @@ instance ToSample Greet where
5252 , ("If you use ?capital=false", Greet "Hello, haskeller")
5353 ]
5454
55+-- We define some introductory sections, these will appear at the top of the
56+-- documentation.
57+--
58+-- We pass them in with 'docsWith', below. If you only want to add
59+-- introductions, you may use 'docsWithIntros'
5560intro1 :: DocIntro
5661intro1 = DocIntro "On proper introductions." -- The title
5762 [ "Hello there."
@@ -78,8 +83,11 @@ type TestApi =
7883testApi :: Proxy TestApi
7984testApi = Proxy
8085
81−extras :: ExtraInfo TestApi
82−extras =
86+-- Build some extra information for the DELETE /greet/:greetid endpoint. We
87+-- want to add documentation about a secret unicorn header and some extra
88+-- notes.
89+extra :: ExtraInfo TestApi
90+extra =
8391 safeInfo (Proxy :: Proxy ("greet" :> Capture "greetid" Text :> Delete)) $
8492 defAction & headers <>~ ["unicorns"]
8593 & notes <>~ [ DocNote "Title" ["This is some text"]
@@ -90,11 +98,11 @@ extras =
9098-- is derived from the type as well as from
9199-- the 'ToCapture', 'ToParam' and 'ToSample' instances from above.
92100--
93−-- If you didn't want intros you could just call:
101+-- If you didn't want intros and extra information, you could just call:
94102--
95−-- > docs testAPI
103+-- > docs testAPI :: API
96104docsGreet :: API
97−docsGreet = docsWith [intro1, intro2] extras testApi
105+docsGreet = docsWith [intro1, intro2] extra testApi
98106
99107main :: IO ()
100108main = putStrLn $ markdown docsGreet
example/greet.md+13−3
@@ -37,7 +37,7 @@ You'll also note that multiple intros are possible.
3737
3838- *name*: name of the person to greet
3939
40−#### Matrix Parameters**:
40+#### Matrix Parameters:
4141
4242**hello**:
4343
@@ -47,7 +47,6 @@ You'll also note that multiple intros are possible.
4747
4848
4949
50−
5150#### GET Parameters:
5251
5352 - capital
@@ -72,13 +71,24 @@ You'll also note that multiple intros are possible.
7271
7372## DELETE /greet/:greetid
7473
74+#### Title
75+
76+This is some text
77+
78+#### Second secton
79+
80+And some more
81+
7582#### Captures:
7683
7784- *greetid*: identifier of the greet msg to remove
7885
86+
87+- This endpoint is sensitive to the value of the **unicorns** HTTP header.
88+
7989#### Response:
8090
81− - Status code 204
91+ - Status code 200
8292 - No response body
8393
8494
src/Servant/Docs.hs+54−18
@@ -91,6 +91,11 @@
9191-- > , ("If you use ?capital=false", Greet "Hello, haskeller")
9292-- > ]
9393-- >
94+-- > -- We define some introductory sections, these will appear at the top of the
95+-- > -- documentation.
96+-- > --
97+-- > -- We pass them in with 'docsWith', below. If you only want to add
98+-- > -- introductions, you may use 'docsWithIntros'
9499-- > intro1 :: DocIntro
95100-- > intro1 = DocIntro "On proper introductions." -- The title
96101-- > [ "Hello there."
@@ -117,15 +122,26 @@
117122-- > testApi :: Proxy TestApi
118123-- > testApi = Proxy
119124-- >
125+-- > -- Build some extra information for the DELETE /greet/:greetid endpoint. We
126+-- > -- want to add documentation about a secret unicorn header and some extra
127+-- > -- notes.
128+-- > extra :: ExtraInfo TestApi
129+-- > extra =
130+-- > safeInfo (Proxy :: Proxy ("greet" :> Capture "greetid" Text :> Delete)) $
131+-- > defAction & headers <>~ ["unicorns"]
132+-- > & notes <>~ [ DocNote "Title" ["This is some text"]
133+-- > , DocNote "Second secton" ["And some more"]
134+-- > ]
135+-- >
120136-- > -- Generate the data that lets us have API docs. This
121137-- > -- is derived from the type as well as from
122138-- > -- the 'ToCapture', 'ToParam' and 'ToSample' instances from above.
123139-- > --
124−-- > -- If you didn't want intros you could just call:
140+-- > -- If you didn't want intros and extra information, you could just call:
125141-- > --
126−-- > -- > docs testAPI
142+-- > -- > docs testAPI :: API
127143-- > docsGreet :: API
128−-- > docsGreet = docsWithIntros [intro1, intro2] testApi
144+-- > docsGreet = docsWith [intro1, intro2] extra testApi
129145-- >
130146-- > main :: IO ()
131147-- > main = putStrLn $ markdown docsGreet
@@ -298,6 +314,17 @@ data DocNote = DocNote
298314 , _noteBody :: [String]
299315 } deriving (Eq, Show)
300316
317+-- | Type of extra information that a user may wish to "union" with their
318+-- documentation.
319+--
320+-- These are intended to be built using safeInfo.
321+-- Multiple ExtraInfo may be combined with the monoid instance.
322+newtype ExtraInfo layout = ExtraInfo (HashMap Endpoint Action)
323+instance Monoid (ExtraInfo a) where
324+ mempty = ExtraInfo mempty
325+ ExtraInfo a `mappend` ExtraInfo b =
326+ ExtraInfo $ HM.unionWith combineAction a b
327+
301328-- | Type of GET parameter:
302329--
303330-- - Normal corresponds to @QueryParam@, i.e your usual GET parameter
@@ -405,13 +432,6 @@ makeLenses ''Action
405432docs :: HasDocs layout => Proxy layout -> API
406433docs p = docsFor p (defEndpoint, defAction)
407434
408−
409−newtype ExtraInfo layout = ExtraInfo (HashMap Endpoint Action)
410−instance Monoid (ExtraInfo a) where
411− mempty = ExtraInfo mempty
412− ExtraInfo a `mappend` ExtraInfo b =
413− ExtraInfo $ HM.unionWith combineAction a b
414−
415435-- | Closed type family, check if endpoint is exactly within API.
416436
417437-- We aren't sure what affects how an Endpoint is built up, so we require an
@@ -421,6 +441,18 @@ type family IsIn (endpoint :: *) (api :: *) :: Constraint where
421441 IsIn (e :> sa) (e :> sb) = IsIn sa sb
422442 IsIn e e = ()
423443
444+-- | Create an 'ExtraInfo' that is garunteed to be within the given API layout.
445+--
446+-- The safety here is to ensure that you only add custom documentation to an
447+-- endpoint that actually exists within your API.
448+--
449+-- > extra :: ExtraInfo TestApi
450+-- > extra =
451+-- > safeInfo (Proxy :: Proxy ("greet" :> Capture "greetid" Text :> Delete)) $
452+-- > defAction & headers <>~ ["unicorns"]
453+-- > & notes <>~ [ DocNote "Title" ["This is some text"]
454+-- > , DocNote "Second secton" ["And some more"]
455+-- > ]
424456
425457safeInfo :: (IsIn endpoint layout, HasLink endpoint, HasDocs endpoint)
426458 => Proxy endpoint -> Action -> ExtraInfo layout
@@ -430,12 +462,18 @@ safeInfo p action =
430462 -- point at one endpoint.
431463 in ExtraInfo $ api ^. apiEndpoints & traversed .~ action
432464
433−-- | Generate documentation given some initial state, in which you may wish to
434−-- note that certain endpoints are special in some way.
465+-- | Generate documentation given some extra introductions (in the form of
466+-- 'DocInfo') and some extra endpoint documentation (in the form of
467+-- 'ExtraInfo'.
435468--
436−-- If you only want to add an introduction, use 'docsWithIntros'.
469+-- The extra introductions will be prepended to the top of the documentation,
470+-- before the specific endpoint documentation. The extra endpoint documentation
471+-- will be "unioned" with the automatically generated endpoint documentation.
472+--
473+-- You are expected to build up the ExtraInfo with the Monoid instance and
474+-- 'safeInfo'.
437475--
438−-- You are expected to build up the SafeMap with safeEntry
476+-- If you only want to add an introduction, use 'docsWithIntros'.
439477docsWith :: HasDocs layout
440478 => [DocIntro]
441479 -> ExtraInfo layout
@@ -485,7 +523,7 @@ class HasDocs layout where
485523-- You can also instantiate this class using 'toSamples' instead of
486524-- 'toSample': it lets you specify different responses along with
487525-- some context (as 'Text') that explains when you're supposed to
488−-- get the corresponding response.
526+-- get the corresponding response.
489527class ToJSON a => ToSample a where
490528 {-# MINIMAL (toSample | toSamples) #-}
491529 toSample :: Maybe a
@@ -588,9 +626,7 @@ markdown api = unlines $
588626 mxParamsStr l =
589627 "#### Matrix Parameters:" :
590628 "" :
591− map segmentStr l ++
592− "" :
593− []
629+ map segmentStr l
594630 segmentStr :: (String, [DocQueryParam]) -> String
595631 segmentStr (segment, l) = unlines $
596632 ("**" ++ segment ++ "**:") :