2014-11-27 18:28:01 +01:00
|
|
|
-------------------------------------------------------------------------------
|
2015-04-08 16:27:38 +02:00
|
|
|
-- | This module lets you get API docs for free. It lets you generate
|
2014-11-27 18:28:01 +01:00
|
|
|
-- an 'API' from the type that represents your API using 'docs':
|
|
|
|
--
|
|
|
|
-- @docs :: 'HasDocs' api => 'Proxy' api -> 'API'@
|
|
|
|
--
|
2015-04-08 16:27:38 +02:00
|
|
|
-- Alternatively, if you wish to add one or more introductions to your
|
2015-01-30 05:45:00 +01:00
|
|
|
-- documentation, use 'docsWithIntros':
|
|
|
|
--
|
2015-04-08 16:27:38 +02:00
|
|
|
-- @'docsWithIntros' :: 'HasDocs' api => [DocIntro] -> 'Proxy' api -> 'API'@
|
2015-01-30 05:45:00 +01:00
|
|
|
--
|
|
|
|
-- You can then call 'markdown' on the 'API' value:
|
2014-11-27 18:28:01 +01:00
|
|
|
--
|
2015-04-08 16:27:38 +02:00
|
|
|
-- @'markdown' :: 'API' -> String@
|
2014-11-27 18:28:01 +01:00
|
|
|
--
|
|
|
|
-- or define a custom pretty printer:
|
|
|
|
--
|
|
|
|
-- @yourPrettyDocs :: 'API' -> String -- or blaze-html's HTML, or ...@
|
|
|
|
--
|
|
|
|
-- The only thing you'll need to do will be to implement some classes
|
|
|
|
-- for your captures, get parameters and request or response bodies.
|
|
|
|
--
|
2015-04-08 16:27:38 +02:00
|
|
|
-- Here is a complete example that you can run to see the markdown pretty
|
|
|
|
-- printer in action:
|
2014-11-27 18:28:01 +01:00
|
|
|
--
|
2015-02-23 00:23:12 +01:00
|
|
|
-- > {-# LANGUAGE DataKinds #-}
|
|
|
|
-- > {-# LANGUAGE DeriveGeneric #-}
|
|
|
|
-- > {-# LANGUAGE FlexibleInstances #-}
|
|
|
|
-- > {-# LANGUAGE MultiParamTypeClasses #-}
|
|
|
|
-- > {-# LANGUAGE OverloadedStrings #-}
|
|
|
|
-- > {-# LANGUAGE TypeOperators #-}
|
2015-01-30 05:45:00 +01:00
|
|
|
-- > {-# OPTIONS_GHC -fno-warn-orphans #-}
|
2015-05-14 01:01:41 +02:00
|
|
|
-- > import Control.Lens
|
2015-01-30 05:45:00 +01:00
|
|
|
-- > import Data.Aeson
|
2014-11-27 18:28:01 +01:00
|
|
|
-- > import Data.Proxy
|
2015-02-23 00:23:12 +01:00
|
|
|
-- > import Data.String.Conversions
|
|
|
|
-- > import Data.Text (Text)
|
2015-01-30 05:45:00 +01:00
|
|
|
-- > import GHC.Generics
|
|
|
|
-- > import Servant.API
|
|
|
|
-- > import Servant.Docs
|
2014-11-27 18:28:01 +01:00
|
|
|
-- >
|
2015-01-30 05:45:00 +01:00
|
|
|
-- > -- * Example
|
|
|
|
-- >
|
|
|
|
-- > -- | A greet message data type
|
|
|
|
-- > newtype Greet = Greet Text
|
2014-11-27 18:28:01 +01:00
|
|
|
-- > deriving (Generic, Show)
|
|
|
|
-- >
|
2015-02-23 00:23:12 +01:00
|
|
|
-- > -- | We can get JSON support automatically. This will be used to parse
|
|
|
|
-- > -- and encode a Greeting as 'JSON'.
|
2014-11-27 18:28:01 +01:00
|
|
|
-- > instance FromJSON Greet
|
|
|
|
-- > instance ToJSON Greet
|
|
|
|
-- >
|
2015-02-23 00:23:12 +01:00
|
|
|
-- > -- | We can also implement 'MimeRender' for additional formats like 'PlainText'.
|
|
|
|
-- > instance MimeRender PlainText Greet where
|
2015-05-14 01:01:41 +02:00
|
|
|
-- > mimeRender Proxy (Greet s) = "\"" <> cs s <> "\""
|
2015-02-23 00:23:12 +01:00
|
|
|
-- >
|
2015-01-30 05:45:00 +01:00
|
|
|
-- > -- We add some useful annotations to our captures,
|
|
|
|
-- > -- query parameters and request body to make the docs
|
|
|
|
-- > -- really helpful.
|
|
|
|
-- > instance ToCapture (Capture "name" Text) where
|
|
|
|
-- > toCapture _ = DocCapture "name" "name of the person to greet"
|
2014-11-27 18:28:01 +01:00
|
|
|
-- >
|
2015-01-30 05:45:00 +01:00
|
|
|
-- > instance ToCapture (Capture "greetid" Text) where
|
|
|
|
-- > toCapture _ = DocCapture "greetid" "identifier of the greet msg to remove"
|
2014-11-27 18:28:01 +01:00
|
|
|
-- >
|
|
|
|
-- > instance ToParam (QueryParam "capital" Bool) where
|
|
|
|
-- > toParam _ =
|
|
|
|
-- > DocQueryParam "capital"
|
|
|
|
-- > ["true", "false"]
|
2015-01-30 05:45:00 +01:00
|
|
|
-- > "Get the greeting message in uppercase (true) or not (false).\
|
|
|
|
-- > \Default is false."
|
|
|
|
-- > Normal
|
2014-11-27 18:28:01 +01:00
|
|
|
-- >
|
2015-01-30 05:57:56 +01:00
|
|
|
-- > instance ToParam (MatrixParam "lang" String) where
|
|
|
|
-- > toParam _ =
|
|
|
|
-- > DocQueryParam "lang"
|
|
|
|
-- > ["en", "sv", "fr"]
|
|
|
|
-- > "Get the greeting message selected language. Default is en."
|
|
|
|
-- > Normal
|
|
|
|
-- >
|
2015-09-24 14:25:58 +02:00
|
|
|
-- > instance ToSample Greet where
|
2015-05-03 01:49:23 +02:00
|
|
|
-- > toSample _ = Just $ Greet "Hello, haskeller!"
|
2015-01-30 05:45:00 +01:00
|
|
|
-- >
|
2015-05-03 01:49:23 +02:00
|
|
|
-- > toSamples _ =
|
2015-01-30 05:45:00 +01:00
|
|
|
-- > [ ("If you use ?capital=true", Greet "HELLO, HASKELLER")
|
|
|
|
-- > , ("If you use ?capital=false", Greet "Hello, haskeller")
|
|
|
|
-- > ]
|
|
|
|
-- >
|
2015-02-18 02:49:08 +01:00
|
|
|
-- > -- We define some introductory sections, these will appear at the top of the
|
|
|
|
-- > -- documentation.
|
|
|
|
-- > --
|
|
|
|
-- > -- We pass them in with 'docsWith', below. If you only want to add
|
|
|
|
-- > -- introductions, you may use 'docsWithIntros'
|
2015-01-30 05:45:00 +01:00
|
|
|
-- > intro1 :: DocIntro
|
|
|
|
-- > intro1 = DocIntro "On proper introductions." -- The title
|
|
|
|
-- > [ "Hello there."
|
|
|
|
-- > , "As documentation is usually written for humans, it's often useful \
|
|
|
|
-- > \to introduce concepts with a few words." ] -- Elements are paragraphs
|
|
|
|
-- >
|
|
|
|
-- > intro2 :: DocIntro
|
|
|
|
-- > intro2 = DocIntro "This title is below the last"
|
|
|
|
-- > [ "You'll also note that multiple intros are possible." ]
|
2014-11-27 18:28:01 +01:00
|
|
|
-- >
|
|
|
|
-- >
|
|
|
|
-- > -- API specification
|
|
|
|
-- > type TestApi =
|
2015-02-23 00:23:12 +01:00
|
|
|
-- > -- GET /hello/:name?capital={true, false} returns a Greet as JSON or PlainText
|
|
|
|
-- > "hello" :> MatrixParam "lang" String :> Capture "name" Text :> QueryParam "capital" Bool :> Get '[JSON, PlainText] Greet
|
2015-01-30 05:45:00 +01:00
|
|
|
-- >
|
|
|
|
-- > -- POST /greet with a Greet as JSON in the request body,
|
|
|
|
-- > -- returns a Greet as JSON
|
2015-02-19 00:59:24 +01:00
|
|
|
-- > :<|> "greet" :> ReqBody '[JSON] Greet :> Post '[JSON] Greet
|
2015-01-30 05:45:00 +01:00
|
|
|
-- >
|
|
|
|
-- > -- DELETE /greet/:greetid
|
2015-05-14 01:01:41 +02:00
|
|
|
-- > :<|> "greet" :> Capture "greetid" Text :> Delete '[JSON] ()
|
2014-11-27 18:28:01 +01:00
|
|
|
-- >
|
|
|
|
-- > testApi :: Proxy TestApi
|
|
|
|
-- > testApi = Proxy
|
|
|
|
-- >
|
2015-02-18 02:49:08 +01:00
|
|
|
-- > -- Build some extra information for the DELETE /greet/:greetid endpoint. We
|
|
|
|
-- > -- want to add documentation about a secret unicorn header and some extra
|
|
|
|
-- > -- notes.
|
|
|
|
-- > extra :: ExtraInfo TestApi
|
|
|
|
-- > extra =
|
2015-05-14 01:01:41 +02:00
|
|
|
-- > extraInfo (Proxy :: Proxy ("greet" :> Capture "greetid" Text :> Delete '[JSON] ())) $
|
2015-02-18 02:49:08 +01:00
|
|
|
-- > defAction & headers <>~ ["unicorns"]
|
|
|
|
-- > & notes <>~ [ DocNote "Title" ["This is some text"]
|
|
|
|
-- > , DocNote "Second secton" ["And some more"]
|
|
|
|
-- > ]
|
|
|
|
-- >
|
2015-01-30 05:45:00 +01:00
|
|
|
-- > -- Generate the data that lets us have API docs. This
|
|
|
|
-- > -- is derived from the type as well as from
|
|
|
|
-- > -- the 'ToCapture', 'ToParam' and 'ToSample' instances from above.
|
|
|
|
-- > --
|
2015-02-18 02:49:08 +01:00
|
|
|
-- > -- If you didn't want intros and extra information, you could just call:
|
2015-01-30 05:45:00 +01:00
|
|
|
-- > --
|
2015-02-18 02:49:08 +01:00
|
|
|
-- > -- > docs testAPI :: API
|
2015-01-30 05:45:00 +01:00
|
|
|
-- > docsGreet :: API
|
2015-02-18 02:49:08 +01:00
|
|
|
-- > docsGreet = docsWith [intro1, intro2] extra testApi
|
2014-11-27 18:28:01 +01:00
|
|
|
-- >
|
|
|
|
-- > main :: IO ()
|
2015-01-30 05:45:00 +01:00
|
|
|
-- > main = putStrLn $ markdown docsGreet
|
2014-11-27 18:28:01 +01:00
|
|
|
module Servant.Docs
|
|
|
|
( -- * 'HasDocs' class and key functions
|
2015-02-07 05:17:39 +01:00
|
|
|
HasDocs(..), docs, markdown
|
|
|
|
-- * Generating docs with extra information
|
2015-09-21 12:36:57 +02:00
|
|
|
, docsWith, docsWithIntros, docsWithOptions
|
|
|
|
, ExtraInfo(..), extraInfo
|
|
|
|
, DocOptions(..) , defaultDocOptions, maxSamples
|
2014-11-27 18:28:01 +01:00
|
|
|
|
|
|
|
, -- * Classes you need to implement for your types
|
2015-09-13 23:36:30 +02:00
|
|
|
<<<<<<< HEAD
|
2014-11-27 18:28:01 +01:00
|
|
|
ToSample(..)
|
2015-09-19 01:27:51 +02:00
|
|
|
, toSample
|
|
|
|
, noSamples
|
|
|
|
, singleSample
|
2015-09-21 11:51:00 +02:00
|
|
|
, samples
|
2015-09-13 23:36:30 +02:00
|
|
|
ToAuthInfo(..)
|
2014-11-27 18:28:01 +01:00
|
|
|
, sampleByteString
|
2015-01-04 16:38:50 +01:00
|
|
|
, sampleByteStrings
|
2014-11-27 18:28:01 +01:00
|
|
|
, ToParam(..)
|
|
|
|
, ToCapture(..)
|
|
|
|
|
|
|
|
, -- * ADTs to represent an 'API'
|
|
|
|
Method(..)
|
|
|
|
, Endpoint, path, method, defEndpoint
|
2015-05-09 16:06:11 +02:00
|
|
|
, API, apiIntros, apiEndpoints, emptyAPI
|
2015-09-13 23:36:30 +02:00
|
|
|
, AuthenticationInfo(..), authIntro, authDataRequired
|
2014-11-27 18:28:01 +01:00
|
|
|
, DocCapture(..), capSymbol, capDesc
|
|
|
|
, DocQueryParam(..), ParamKind(..), paramName, paramValues, paramDesc, paramKind
|
2015-01-23 02:19:37 +01:00
|
|
|
, DocNote(..), noteTitle, noteBody
|
2015-05-09 16:06:11 +02:00
|
|
|
, DocIntro(..), introTitle, introBody
|
2015-04-08 16:27:38 +02:00
|
|
|
, Response(..), respStatus, respTypes, respBody, defResponse
|
2015-09-13 23:36:30 +02:00
|
|
|
, Action, authInfo, captures, headers, notes, params, rqtypes, rqbody, response, defAction
|
2014-11-27 18:28:01 +01:00
|
|
|
, single
|
|
|
|
) where
|
|
|
|
|
2015-08-17 23:56:29 +02:00
|
|
|
import Servant.Docs.Internal
|