git.iko.soy/typeable/servant
on master help sign in
Improve documentation.
b935f28Christian Marie
example/greet.hs+13−5
@@ -52,6 +52,11 @@ instance ToSample Greet where
52 , ("If you use ?capital=false", Greet "Hello, haskeller")
52 , ("If you use ?capital=false", Greet "Hello, haskeller")
53 ]
53 ]
54
54
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'
55intro1 :: DocIntro
60intro1 :: DocIntro
56intro1 = DocIntro "On proper introductions." -- The title
61intro1 = DocIntro "On proper introductions." -- The title
57 [ "Hello there."
62 [ "Hello there."
@@ -78,8 +83,11 @@ type TestApi =
78testApi :: Proxy TestApi
83testApi :: Proxy TestApi
79testApi = Proxy
84testApi = Proxy
80
85
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.
81−extras :: ExtraInfo TestApi
89+extra :: ExtraInfo TestApi
82−extras =
90+extra =
83 safeInfo (Proxy :: Proxy ("greet" :> Capture "greetid" Text :> Delete)) $
91 safeInfo (Proxy :: Proxy ("greet" :> Capture "greetid" Text :> Delete)) $
84 defAction & headers <>~ ["unicorns"]
92 defAction & headers <>~ ["unicorns"]
85 & notes <>~ [ DocNote "Title" ["This is some text"]
93 & notes <>~ [ DocNote "Title" ["This is some text"]
@@ -90,11 +98,11 @@ extras =
90-- is derived from the type as well as from
98-- is derived from the type as well as from
91-- the 'ToCapture', 'ToParam' and 'ToSample' instances from above.
99-- the 'ToCapture', 'ToParam' and 'ToSample' instances from above.
92--
100--
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:
94--
102--
95−-- > docs testAPI
103+-- > docs testAPI :: API
96docsGreet :: API
104docsGreet :: API
97−docsGreet = docsWith [intro1, intro2] extras testApi
105+docsGreet = docsWith [intro1, intro2] extra testApi
98
106
99main :: IO ()
107main :: IO ()
100main = putStrLn $ markdown docsGreet
108main = putStrLn $ markdown docsGreet
example/greet.md+13−3
@@ -37,7 +37,7 @@ You'll also note that multiple intros are possible.
37
37
38- *name*: name of the person to greet
38- *name*: name of the person to greet
39
39
40−#### Matrix Parameters**:
40+#### Matrix Parameters:
41
41
42**hello**:
42**hello**:
43
43
@@ -47,7 +47,6 @@ You'll also note that multiple intros are possible.
47
47
48
48
49
49
50−
51#### GET Parameters:
50#### GET Parameters:
52
51
53 - capital
52 - capital
@@ -72,13 +71,24 @@ You'll also note that multiple intros are possible.
72
71
73## DELETE /greet/:greetid
72## DELETE /greet/:greetid
74
73
74+#### Title
75+
76+This is some text
77+
78+#### Second secton
79+
80+And some more
81+
75#### Captures:
82#### Captures:
76
83
77- *greetid*: identifier of the greet msg to remove
84- *greetid*: identifier of the greet msg to remove
78
85
86+
87+- This endpoint is sensitive to the value of the **unicorns** HTTP header.
88+
79#### Response:
89#### Response:
80
90
81− - Status code 204
91+ - Status code 200
82 - No response body
92 - No response body
83
93
84
94
src/Servant/Docs.hs+54−18
@@ -91,6 +91,11 @@
91-- > , ("If you use ?capital=false", Greet "Hello, haskeller")
91-- > , ("If you use ?capital=false", Greet "Hello, haskeller")
92-- > ]
92-- > ]
93-- >
93-- >
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'
94-- > intro1 :: DocIntro
99-- > intro1 :: DocIntro
95-- > intro1 = DocIntro "On proper introductions." -- The title
100-- > intro1 = DocIntro "On proper introductions." -- The title
96-- > [ "Hello there."
101-- > [ "Hello there."
@@ -117,15 +122,26 @@
117-- > testApi :: Proxy TestApi
122-- > testApi :: Proxy TestApi
118-- > testApi = Proxy
123-- > testApi = Proxy
119-- >
124-- >
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+-- >
120-- > -- Generate the data that lets us have API docs. This
136-- > -- Generate the data that lets us have API docs. This
121-- > -- is derived from the type as well as from
137-- > -- is derived from the type as well as from
122-- > -- the 'ToCapture', 'ToParam' and 'ToSample' instances from above.
138-- > -- the 'ToCapture', 'ToParam' and 'ToSample' instances from above.
123-- > --
139-- > --
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:
125-- > --
141-- > --
126−-- > -- > docs testAPI
142+-- > -- > docs testAPI :: API
127-- > docsGreet :: API
143-- > docsGreet :: API
128−-- > docsGreet = docsWithIntros [intro1, intro2] testApi
144+-- > docsGreet = docsWith [intro1, intro2] extra testApi
129-- >
145-- >
130-- > main :: IO ()
146-- > main :: IO ()
131-- > main = putStrLn $ markdown docsGreet
147-- > main = putStrLn $ markdown docsGreet
@@ -298,6 +314,17 @@ data DocNote = DocNote
298 , _noteBody :: [String]
314 , _noteBody :: [String]
299 } deriving (Eq, Show)
315 } deriving (Eq, Show)
300
316
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+
301-- | Type of GET parameter:
328-- | Type of GET parameter:
302--
329--
303-- - Normal corresponds to @QueryParam@, i.e your usual GET parameter
330-- - Normal corresponds to @QueryParam@, i.e your usual GET parameter
@@ -405,13 +432,6 @@ makeLenses ''Action
405docs :: HasDocs layout => Proxy layout -> API
432docs :: HasDocs layout => Proxy layout -> API
406docs p = docsFor p (defEndpoint, defAction)
433docs p = docsFor p (defEndpoint, defAction)
407
434
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−
415-- | Closed type family, check if endpoint is exactly within API.
435-- | Closed type family, check if endpoint is exactly within API.
416
436
417-- We aren't sure what affects how an Endpoint is built up, so we require an
437-- 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
421 IsIn (e :> sa) (e :> sb) = IsIn sa sb
441 IsIn (e :> sa) (e :> sb) = IsIn sa sb
422 IsIn e e = ()
442 IsIn e e = ()
423
443
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+-- > ]
424
456
425safeInfo :: (IsIn endpoint layout, HasLink endpoint, HasDocs endpoint)
457safeInfo :: (IsIn endpoint layout, HasLink endpoint, HasDocs endpoint)
426 => Proxy endpoint -> Action -> ExtraInfo layout
458 => Proxy endpoint -> Action -> ExtraInfo layout
@@ -430,12 +462,18 @@ safeInfo p action =
430 -- point at one endpoint.
462 -- point at one endpoint.
431 in ExtraInfo $ api ^. apiEndpoints & traversed .~ action
463 in ExtraInfo $ api ^. apiEndpoints & traversed .~ action
432
464
433−-- | Generate documentation given some initial state, in which you may wish to
465+-- | Generate documentation given some extra introductions (in the form of
434−-- note that certain endpoints are special in some way.
466+-- 'DocInfo') and some extra endpoint documentation (in the form of
467+-- 'ExtraInfo'.
435--
468--
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'.
437--
475--
438−-- You are expected to build up the SafeMap with safeEntry
476+-- If you only want to add an introduction, use 'docsWithIntros'.
439docsWith :: HasDocs layout
477docsWith :: HasDocs layout
440 => [DocIntro]
478 => [DocIntro]
441 -> ExtraInfo layout
479 -> ExtraInfo layout
@@ -485,7 +523,7 @@ class HasDocs layout where
485-- You can also instantiate this class using 'toSamples' instead of
523-- You can also instantiate this class using 'toSamples' instead of
486-- 'toSample': it lets you specify different responses along with
524-- 'toSample': it lets you specify different responses along with
487-- some context (as 'Text') that explains when you're supposed to
525-- some context (as 'Text') that explains when you're supposed to
488−-- get the corresponding response.
526+-- get the corresponding response.
489class ToJSON a => ToSample a where
527class ToJSON a => ToSample a where
490 {-# MINIMAL (toSample | toSamples) #-}
528 {-# MINIMAL (toSample | toSamples) #-}
491 toSample :: Maybe a
529 toSample :: Maybe a
@@ -588,9 +626,7 @@ markdown api = unlines $
588 mxParamsStr l =
626 mxParamsStr l =
589 "#### Matrix Parameters:" :
627 "#### Matrix Parameters:" :
590 "" :
628 "" :
591− map segmentStr l ++
629+ map segmentStr l
592− "" :
593− []
594 segmentStr :: (String, [DocQueryParam]) -> String
630 segmentStr :: (String, [DocQueryParam]) -> String
595 segmentStr (segment, l) = unlines $
631 segmentStr (segment, l) = unlines $
596 ("**" ++ segment ++ "**:") :
632 ("**" ++ segment ++ "**:") :