packages feed

servant-docs 0.11.9 → 0.13.1

raw patch · 7 files changed

Files

CHANGELOG.md view
@@ -1,6 +1,29 @@ [The latest version of this document is on GitHub.](https://github.com/haskell-servant/servant/blob/master/servant-docs/CHANGELOG.md) [Changelog for `servant` package contains significant entries for all core packages.](https://github.com/haskell-servant/servant/blob/master/servant/CHANGELOG.md) +0.13.1+------++- Compatibility with newer dependencies and newer GHCs.++0.13+----++- WithResource combinator for Servant-managed resources. [#1630](https://github.com/haskell-servant/servant/pull/1630)++  For servant-docs, this meant the addition of `instance HasDocs api => HasDocs (WithResource res :> api)`++- Compatibility with GHC series 9.2, 9.4, 9.6++0.12+----++### Significant changes++- Generate sample cURL requests+  ([#1401](https://github.com/haskell-servant/servant/pull/1401/files)).+  Breaking change: requires sample header values to be supplied with `headers`.+ 0.11.9 ------ 
example/greet.hs view
@@ -9,8 +9,7 @@ import           Data.Aeson import           Data.Proxy import           Data.String.Conversions-import           Data.Text-                 (Text)+import           Data.Text (Text) import           GHC.Generics import           Servant.API import           Servant.Docs@@ -75,7 +74,7 @@ -- API specification type TestApi =        -- GET /hello/:name?capital={true, false}  returns a Greet as JSON or PlainText-       "hello" :> Capture "name" Text :> QueryParam "capital" Bool :> Get '[JSON, PlainText] Greet+       "hello" :> Capture "name" Text :> Header "X-Num-Fairies" Int :> QueryParam "capital" Bool :> Get '[JSON, PlainText] Greet         -- POST /greet with a Greet as JSON in the request body,        --             returns a Greet as JSON@@ -93,9 +92,9 @@ extra :: ExtraInfo TestApi extra =     extraInfo (Proxy :: Proxy ("greet" :> Capture "greetid" Text :> Delete '[JSON] NoContent)) $-             defAction & headers <>~ ["unicorns"]+             defAction & headers <>~ [("X-Num-Unicorns", "1")]                        & notes   <>~ [ DocNote "Title" ["This is some text"]-                                     , DocNote "Second secton" ["And some more"]+                                     , DocNote "Second section" ["And some more"]                                      ]  -- Generate the data that lets us have API docs. This@@ -109,4 +108,4 @@ docsGreet = docsWith defaultDocOptions [intro1, intro2] extra testApi  main :: IO ()-main = putStrLn $ markdown docsGreet+main = putStrLn $ markdownWith (defRenderingOptions { _renderCurlBasePath = Just "http://localhost:80" }) docsGreet
golden/comprehensive.md view
@@ -12,7 +12,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -30,7 +30,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -48,7 +48,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -70,7 +70,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -92,7 +92,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -114,7 +114,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -135,7 +135,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -160,7 +160,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -178,7 +178,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -200,7 +200,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -218,7 +218,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json 17 ``` @@ -240,7 +240,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -262,7 +262,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -280,7 +280,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -298,7 +298,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -316,7 +316,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -341,7 +341,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -366,7 +366,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -392,7 +392,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -410,7 +410,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json 17 ``` @@ -446,7 +446,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -461,7 +461,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json 17 ``` @@ -477,7 +477,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -492,7 +492,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json 17 ``` @@ -508,7 +508,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -526,10 +526,28 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` +## GET /resource++### Response:++- Status code 200+- Headers: []++- Supported content types are:++    - `application/json;charset=utf-8`+    - `application/json`++- Example (`application/json;charset=utf-8`, `application/json`):++```json++```+ ## GET /streaming  ### Request:@@ -568,7 +586,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` @@ -586,7 +604,7 @@  - Example (`application/json;charset=utf-8`, `application/json`): -```javascript+```json  ``` 
servant-docs.cabal view
@@ -1,6 +1,6 @@-cabal-version:       >=1.10+cabal-version:       2.2 name:                servant-docs-version:             0.11.9+version:             0.13.1  synopsis:            generate API docs for your servant webservice category:            Servant, Web@@ -13,13 +13,13 @@  homepage:            http://docs.servant.dev/ bug-reports:         http://github.com/haskell-servant/servant/issues-license:             BSD3+license:             BSD-3-Clause license-file:        LICENSE author:              Servant Contributors maintainer:          haskell-servant-maintainers@googlegroups.com copyright:           2014-2016 Zalora South East Asia Pte Ltd, 2016-2019 Servant Contributors build-type:          Simple-tested-with: GHC ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.4 || ==8.10.2 || ==9.0.1+tested-with: GHC ==8.10.7, GHC ==9.0.2, GHC ==9.2.8, GHC ==9.4.8, GHC ==9.6.4, GHC ==9.8.2, GHC ==9.10.1  extra-source-files:   CHANGELOG.md@@ -41,25 +41,25 @@   --   -- note: mtl lower bound is so low because of GHC-7.8   build-depends:-      base       >= 4.9      && < 4.16-    , bytestring >= 0.10.8.1 && < 0.12-    , text       >= 1.2.3.0  && < 1.3+      base       >= 4.14     && < 4.21+    , bytestring >= 0.10.8.1 && < 0.13+    , text       >= 1.2.3.0  && < 2.2    -- Servant dependencies   build-depends:-      servant            >= 0.18 && <0.19+      servant            >= 0.20.2 && <0.21    -- Other dependencies: Lower bound around what is in the latest Stackage LTS.   -- Here can be exceptions if we really need features from the newer versions.   build-depends:-      aeson                >= 1.4.1.0  && < 1.6+      aeson                >= 1.4.1.0  && < 3     , aeson-pretty         >= 0.8.5    && < 0.9-    , base-compat          >= 0.10.5   && < 0.12+    , base-compat          >= 0.10.5   && < 0.15     , case-insensitive     >= 1.2.0.11 && < 1.3-    , hashable             >= 1.2.7.0  && < 1.4+    , hashable             >= 1.2.7.0  && < 1.6     , http-media           >= 0.7.1.3  && < 0.9     , http-types           >= 0.12.2   && < 0.13-    , lens                 >= 4.17     && < 5.1+    , lens                 >= 4.17     && < 5.4     , string-conversions   >= 0.4.0.1  && < 0.5     , universe-base        >= 1.1.1    && < 1.2     , unordered-containers >= 0.2.9.0  && < 0.3@@ -102,7 +102,7 @@    -- Additional dependencies   build-depends:-      tasty         >= 1.1.0.4  && < 1.3,+      tasty         >= 1.1.0.4  && < 1.6,       tasty-golden  >= 2.3.2    && < 2.4,       tasty-hunit   >= 0.10.0.1 && < 0.11,-      transformers  >= 0.5.2.0  && < 0.6+      transformers  >= 0.5.2.0  && < 0.7
src/Servant/Docs/Internal.hs view
@@ -25,16 +25,14 @@ import           Control.Arrow                  (second) import           Control.Lens-                 (makeLenses, mapped, over, set, traversed, view, (%~), (&),-                 (.~), (<>~), (^.), (|>))+                 (makeLenses, mapped, each, over, set, to, toListOf, traversed, view,+                 _1, (%~), (&), (.~), (<>~), (^.), (|>)) import qualified Data.ByteString.Char8      as BSC import           Data.ByteString.Lazy.Char8                  (ByteString) import qualified Data.CaseInsensitive       as CI import           Data.Foldable-                 (toList)-import           Data.Foldable-                 (fold)+                 (fold, toList) import           Data.Hashable                  (Hashable) import           Data.HashMap.Strict@@ -52,17 +50,20 @@                  (comparing) import           Data.Proxy                  (Proxy (Proxy))-import           Data.Semigroup-                 (Semigroup (..)) import           Data.String.Conversions                  (cs) import           Data.Text                  (Text, unpack) import           GHC.Generics+                 (Generic, Rep, K1(K1), M1(M1), U1(U1), V1,+                 (:*:)((:*:)), (:+:)(L1, R1))+import qualified GHC.Generics               as G import           GHC.TypeLits import           Servant.API import           Servant.API.ContentTypes+import           Servant.API.TypeErrors import           Servant.API.TypeLevel+import           Servant.API.Generic  import qualified Data.Universe.Helpers      as U @@ -295,7 +296,7 @@ data Action = Action   { _authInfo :: [DocAuthentication]         -- user supplied info   , _captures :: [DocCapture]                -- type collected + user supplied info-  , _headers  :: [Text]                      -- type collected+  , _headers  :: [HTTP.Header]               -- type collected   , _params   :: [DocQueryParam]             -- type collected + user supplied info   , _fragment :: Maybe DocFragment           -- type collected + user supplied info   , _notes    :: [DocNote]                   -- user supplied@@ -356,12 +357,14 @@ -- --   @since 0.11.1 data RenderingOptions = RenderingOptions-  { _requestExamples  :: !ShowContentTypes+  { _requestExamples    :: !ShowContentTypes     -- ^ How many content types to display for request body examples?-  , _responseExamples :: !ShowContentTypes+  , _responseExamples   :: !ShowContentTypes     -- ^ How many content types to display for response body examples?-  , _notesHeading     :: !(Maybe String)+  , _notesHeading       :: !(Maybe String)     -- ^ Optionally group all 'notes' together under a common heading.+  , _renderCurlBasePath :: !(Maybe String)+    -- ^ Optionally render example curl requests under a common base path (e.g. `http://localhost:80`).   } deriving (Show)  -- | Default API generation options.@@ -373,9 +376,10 @@ --   @since 0.11.1 defRenderingOptions :: RenderingOptions defRenderingOptions = RenderingOptions-  { _requestExamples  = AllContentTypes-  , _responseExamples = AllContentTypes-  , _notesHeading     = Nothing+  { _requestExamples    = AllContentTypes+  , _responseExamples   = AllContentTypes+  , _notesHeading       = Nothing+  , _renderCurlBasePath = Nothing   }  -- gimme some lenses@@ -412,7 +416,7 @@ -- > extra :: ExtraInfo TestApi -- > extra = -- >     extraInfo (Proxy :: Proxy ("greet" :> Capture "greetid" Text :> Delete)) $--- >              defAction & headers <>~ ["unicorns"]+-- >              defAction & headers <>~ [("X-Num-Unicorns", 1)] -- >                        & notes   <>~ [ DocNote "Title" ["This is some text"] -- >                                      , DocNote "Second section" ["And some more"] -- >                                      ]@@ -444,7 +448,7 @@       & apiEndpoints %~ HM.unionWith (flip combineAction) endpoints  --- | Generate the docs for a given API that implements 'HasDocs' with with any+-- | Generate the docs for a given API that implements 'HasDocs' with any -- number of introduction(s) docsWithIntros :: HasDocs api => [DocIntro] -> Proxy api -> API docsWithIntros intros = docsWith defaultDocOptions intros mempty@@ -507,7 +511,7 @@  -- | Default sample Generic-based inputs/outputs. defaultSamples :: forall a. (Generic a, GToSample (Rep a)) => Proxy a -> [(Text, a)]-defaultSamples _ = second to <$> gtoSamples (Proxy :: Proxy (Rep a))+defaultSamples _ = second G.to <$> gtoSamples (Proxy :: Proxy (Rep a))  -- | @'ToSample'@ for Generics. --@@ -643,7 +647,7 @@ -- --   @since 0.11.1 markdownWith :: RenderingOptions -> API -> String-markdownWith RenderingOptions{..}  api = unlines $+markdownWith RenderingOptions{..} api = unlines $        introsStr (api ^. apiIntros)     ++ (concatMap (uncurry printEndpoint) . sort . HM.toList $ api ^. apiEndpoints) @@ -654,11 +658,12 @@           notesStr (action ^. notes) ++           authStr (action ^. authInfo) ++           capturesStr (action ^. captures) ++-          headersStr (action ^. headers) +++          headersStr (toListOf (headers . each . _1 . to (T.pack . BSC.unpack . CI.original)) action) ++           paramsStr meth (action ^. params) ++           fragmentStr (action ^. fragment) ++           rqbodyStr (action ^. rqtypes) (action ^. rqbody) ++           responseStr (action ^. response) +++          maybe [] (curlStr endpoint (action ^. headers) (action ^. rqbody)) _renderCurlBasePath ++           []            where str = "## " ++ BSC.unpack meth@@ -809,12 +814,11 @@                 ("text", "html") -> "html"                 ("application", "xml") -> "xml"                 ("text", "xml") -> "xml"-                ("application", "json") -> "javascript"+                ("application", "json") -> "json"                 ("application", "javascript") -> "javascript"                 ("text", "css") -> "css"                 (_, _) -> "" -         contentStr mime_type body =           "" :           "```" <> markdownForType mime_type :@@ -839,6 +843,36 @@                   xs        ->                     formatBodies _responseExamples xs +        curlStr :: Endpoint -> [HTTP.Header] -> [(Text, M.MediaType, ByteString)] -> String -> [String]+        curlStr endpoint hdrs reqBodies basePath =+          [  "### Sample Request:"+          , ""+          , "```bash"+          , "curl -X" ++ BSC.unpack (endpoint ^. method) ++ " \\"+          ] <>+          maybe [] pure mbMediaTypeStr <>+          headersStrs <>+          maybe [] pure mbReqBodyStr <>+          [  "  " ++ basePath ++ showPath (endpoint ^. path)+          , "```"+          , ""+          ]++          where escapeQuotes :: String -> String+                escapeQuotes = concatMap $ \c -> case c of+                  '\"' -> "\\\""+                  _ -> [c]+                mbReqBody = listToMaybe reqBodies+                mbMediaTypeStr = mkMediaTypeStr <$> mbReqBody+                headersStrs = mkHeaderStr <$> hdrs+                mbReqBodyStr = mkReqBodyStr <$> mbReqBody+                mkMediaTypeStr (_, media_type, _) =+                  "  -H \"Content-Type: " ++ show media_type ++ "\" \\"+                mkHeaderStr (hdrName, hdrVal) =+                  "  -H \"" ++ escapeQuotes (cs (CI.original hdrName)) ++ ": " +++                  escapeQuotes (cs hdrVal) ++ "\" \\"+                mkReqBodyStr (_, _, body) = "  -d \"" ++ escapeQuotes (cs body) ++ "\" \\"+ -- * Instances  -- | The generated docs for @a ':<|>' b@ just appends the docs@@ -977,14 +1011,17 @@           status = fromInteger $ natVal (Proxy :: Proxy status)           p = Proxy :: Proxy a -instance (KnownSymbol sym, HasDocs api)+instance (ToHttpApiData a, ToSample a, KnownSymbol sym, HasDocs api)       => HasDocs (Header' mods sym a :> api) where   docsFor Proxy (endpoint, action) =     docsFor subApiP (endpoint, action')      where subApiP = Proxy :: Proxy api-          action' = over headers (|> headername) action-          headername = T.pack $ symbolVal (Proxy :: Proxy sym)+          action' = over headers (|> (headerName, headerVal)) action+          headerName = CI.mk . cs $ symbolVal (Proxy :: Proxy sym)+          headerVal = case toSample (Proxy :: Proxy a) of+            Just x -> cs $ toHeader x+            Nothing -> "<no header sample provided>"  instance (KnownSymbol sym, ToParam (QueryParam' mods sym a), HasDocs api)       => HasDocs (QueryParam' mods sym a :> api) where@@ -1108,12 +1145,21 @@ instance HasDocs api => HasDocs (WithNamedContext name context api) where   docsFor Proxy = docsFor (Proxy :: Proxy api) +instance HasDocs api => HasDocs (WithResource res :> api) where+  docsFor Proxy = docsFor (Proxy :: Proxy api)+ instance (ToAuthInfo (BasicAuth realm usr), HasDocs api) => HasDocs (BasicAuth realm usr :> api) where   docsFor Proxy (endpoint, action) =     docsFor (Proxy :: Proxy api) (endpoint, action')       where         authProxy = Proxy :: Proxy (BasicAuth realm usr)         action' = over authInfo (|> toAuthInfo authProxy) action++instance+  ( HasDocs (ToServantApi api)+  , ErrorIfNoGeneric api+  ) => HasDocs (NamedRoutes api) where+  docsFor Proxy = docsFor (Proxy :: Proxy (ToServantApi api))  -- ToSample instances for simple types instance ToSample NoContent
src/Servant/Docs/Internal/Pretty.hs view
@@ -18,6 +18,7 @@ import           Network.HTTP.Media                  ((//)) import           Servant.API+import           Servant.API.Verbs  -- | PrettyJSON content type. data PrettyJSON@@ -46,6 +47,24 @@     Pretty (Put cs r)     = Put     (Pretty cs) r     Pretty (Delete cs r)  = Delete  (Pretty cs) r     Pretty (Patch cs r)   = Patch   (Pretty cs) r+    Pretty (GetPartialContent cs r)      = GetPartialContent      (Pretty cs) r+    Pretty (PutResetContent cs r)        = PutResetContent        (Pretty cs) r+    Pretty (PatchResetContent cs r)      = PatchResetContent      (Pretty cs) r+    Pretty (DeleteResetContent cs r)     = DeleteResetContent     (Pretty cs) r+    Pretty (PostResetContent cs r)       = PostResetContent       (Pretty cs) r+    Pretty (GetResetContent cs r)        = GetResetContent        (Pretty cs) r+    Pretty (PutNonAuthoritative cs r)    = PutNonAuthoritative    (Pretty cs) r+    Pretty (PatchNonAuthoritative cs r)  = PatchNonAuthoritative  (Pretty cs) r+    Pretty (DeleteNonAuthoritative cs r) = DeleteNonAuthoritative (Pretty cs) r+    Pretty (PostNonAuthoritative cs r)   = PostNonAuthoritative   (Pretty cs) r+    Pretty (GetNonAuthoritative cs r)    = GetNonAuthoritative    (Pretty cs) r+    Pretty (PutAccepted cs r)            = PutAccepted            (Pretty cs) r+    Pretty (PatchAccepted cs r)          = PatchAccepted          (Pretty cs) r+    Pretty (DeleteAccepted cs r)         = DeleteAccepted         (Pretty cs) r+    Pretty (PostAccepted cs r)           = PostAccepted           (Pretty cs) r+    Pretty (GetAccepted cs r)            = GetAccepted            (Pretty cs) r+    Pretty (PutCreated cs r)             = PutCreated             (Pretty cs) r+    Pretty (PostCreated cs r)            = PostCreated            (Pretty cs) r     Pretty (ReqBody cs r) = ReqBody (Pretty cs) r     Pretty (JSON ': xs)   = PrettyJSON ': xs     Pretty (x ': xs)      = x ': Pretty xs
test/Servant/DocsSpec.hs view
@@ -130,7 +130,6 @@       md `shouldContain` "\"dt1field1\":\"field 1\""     it "contains response samples - dt1field2" $       md `shouldContain` "\"dt1field2\":13"-     it "contains request body samples" $       md `shouldContain` "17"