@@ -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 ++ "**:") :