on master help sign in
first shot (doesn't build though) at multiple responses in the docs
commit0edde415bdae7afcb4a43e799d77ecdbcc5e81dd authorAlp Mestanogullari <alpmestan@gmail.com> dateSun 4 Jan 2015, 16:38 (12 years ago) parentb93ff6c
1 file changed+39−19
src/Servant/Docs.hs+39−19
src/Servant/Docs.hs+39−19
@@ -1,10 +1,12 @@
11{-# LANGUAGE TypeFamilies #-}
22{-# LANGUAGE DeriveGeneric #-}
3+{-# LANGUAGE TupleSections #-}
34{-# LANGUAGE TypeOperators #-}
5+{-# LANGUAGE TemplateHaskell #-}
46{-# LANGUAGE FlexibleContexts #-}
57{-# LANGUAGE FlexibleInstances #-}
8+{-# LANGUAGE OverloadedStrings #-}
69{-# LANGUAGE ScopedTypeVariables #-}
7−{-# LANGUAGE TemplateHaskell #-}
810
911-------------------------------------------------------------------------------
1012-- | This module lets you get API docs for free. It lets generate
@@ -83,12 +85,10 @@ module Servant.Docs
8385 ( -- * 'HasDocs' class and key functions
8486 HasDocs(..), docs, markdown
8587
86− {- , -- * Serving the documentation
87− serveDocumentation -}
88−
8988 , -- * Classes you need to implement for your types
9089 ToSample(..)
9190 , sampleByteString
91+ , sampleByteStrings
9292 , ToParam(..)
9393 , ToCapture(..)
9494
@@ -114,6 +114,7 @@ import Data.ByteString.Lazy.Char8 (ByteString)
114114import Data.Hashable
115115import Data.HashMap.Strict (HashMap)
116116import Data.List
117+import Data.Maybe (listToMaybe)
117118import Data.Monoid
118119import Data.Proxy
119120import Data.Text (Text, pack, unpack)
@@ -123,6 +124,7 @@ import GHC.TypeLits
123124import Servant.API
124125
125126import qualified Data.HashMap.Strict as HM
127+import qualified Data.Text as T
126128
127129-- | Supported HTTP request methods
128130data Method = DocDELETE -- ^ the DELETE method
@@ -233,12 +235,12 @@ data ParamKind = Normal | List | Flag
233235-- Can be tweaked with two lenses.
234236--
235237-- > λ> defResponse
236−-- > Response {_respStatus = 200, _respBody = Nothing}
237−-- > λ> defResponse & respStatus .~ 204 & respBody .~ Just "[]"
238−-- > Response {_respStatus = 204, _respBody = Just "[]"}
238+-- > Response {_respStatus = 200, _respBody = []}
239+-- > λ> defResponse & respStatus .~ 204 & respBody .~ [("If everything goes well", "{ \"status\": \"ok\" }")]
240+-- > Response {_respStatus = 204, _respBody = [("If everything goes well", "{ \"status\": \"ok\" }")]}
239241data Response = Response
240242 { _respStatus :: Int
241− , _respBody :: Maybe ByteString
243+ , _respBody :: [(Text, ByteString)]
242244 } deriving (Eq, Show)
243245
244246-- | Default response: status code 200, no response body.
@@ -250,7 +252,7 @@ data Response = Response
250252-- > λ> defResponse & respStatus .~ 204 & respBody .~ Just "[]"
251253-- > Response {_respStatus = 204, _respBody = Just "[]"}
252254defResponse :: Response
253−defResponse = Response 200 Nothing
255+defResponse = Response 200 []
254256
255257-- | A datatype that represents everything that can happen
256258-- at an endpoint, with its lenses:
@@ -334,15 +336,29 @@ class HasDocs layout where
334336-- > toSample = Just g
335337-- >
336338-- > where g = Greet "Hello, haskeller!"
339+--
340+-- You can also instantiate this class using 'toSamples' instead of
341+-- 'toSample': it lets you specify different responses along with
342+-- some context (as 'Text') that explains when you're supposed to
343+-- get the corresponding response.
337344class ToJSON a => ToSample a where
345+ {-# MINIMAL (toSample | toSamples) #-}
338346 toSample :: Maybe a
347+ toSample = fmap snd $ listToMaybe samples
348+ where samples = toSamples :: [(Text, a)]
339349
340−instance ToSample () where
341− toSample = Just ()
350+ toSamples :: [(Text, a)]
351+ toSamples = maybe [] (return . ("",)) s
352+ where s = toSample :: Maybe a
342353
343−sampleByteString :: forall a . ToSample a => Proxy a -> Maybe ByteString
354+sampleByteString :: ToSample a => Proxy a -> Maybe ByteString
344355sampleByteString Proxy = fmap encodePretty (toSample :: Maybe a)
345356
357+sampleByteStrings :: ToSample a => Proxy a -> [(Text, ByteString)]
358+sampleByteStrings Proxy = samples & traverse._2 %~ encodePretty
359+
360+ where samples = toSamples :: [(Text, a)]
361+
346362-- | The class that helps us automatically get documentation
347363-- for GET parameters.
348364--
@@ -448,9 +464,13 @@ markdown = unlines . concat . map (uncurry printEndpoint) . HM.toList
448464 "**Response**: " :
449465 "" :
450466 (" - Status code " ++ show (resp ^. respStatus)) :
451− (resp ^. respBody &
452− maybe [" - No response body\n"]
453− (\b -> " - Response body as below." : jsonStr b))
467+ bodies
468+
469+ where bodies = case resp ^. respBody of
470+ [] -> [" - No response body\n"]
471+ [("", r)] -> " - Response body as below." : jsonStr r
472+ xs ->
473+ concatMap (\(ctx, r) -> (" - " <> T.unpack ctx) : jsonStr r) xs
454474
455475-- * Instances
456476
@@ -489,7 +509,7 @@ instance HasDocs Delete where
489509
490510 where endpoint' = endpoint & method .~ DocDELETE
491511
492− action' = action & response.respBody .~ Nothing
512+ action' = action & response.respBody .~ []
493513 & response.respStatus .~ 204
494514
495515instance ToSample a => HasDocs (Get a) where
@@ -497,7 +517,7 @@ instance ToSample a => HasDocs (Get a) where
497517 single endpoint' action'
498518
499519 where endpoint' = endpoint & method .~ DocGET
500− action' = action & response.respBody .~ sampleByteString p
520+ action' = action & response.respBody .~ sampleByteStrings p
501521 p = Proxy :: Proxy a
502522
503523instance (KnownSymbol sym, HasDocs sublayout)
@@ -515,7 +535,7 @@ instance ToSample a => HasDocs (Post a) where
515535
516536 where endpoint' = endpoint & method .~ DocPOST
517537
518− action' = action & response.respBody .~ sampleByteString p
538+ action' = action & response.respBody .~ sampleByteStrings p
519539 & response.respStatus .~ 201
520540
521541 p = Proxy :: Proxy a
@@ -526,7 +546,7 @@ instance ToSample a => HasDocs (Put a) where
526546
527547 where endpoint' = endpoint & method .~ DocPUT
528548
529− action' = action & response.respBody .~ sampleByteString p
549+ action' = action & response.respBody .~ sampleByteStrings p
530550 & response.respStatus .~ 200
531551
532552 p = Proxy :: Proxy a