-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | generate API docs for your servant webservice -- -- Library for generating API docs from a servant API definition. -- -- Runnable example here. @package servant-docs @version 0.3 -- | This module lets you get API docs for free. It lets generate an -- API from the type that represents your API using docs: -- --
-- docs :: HasDocs api => Proxy api -> API ---- -- You can then call markdown on it: -- --
-- markdown :: API -> String ---- -- 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. -- -- Here's a little (but complete) example that you can run to see the -- markdown pretty printer in action: -- --
-- {-# LANGUAGE DataKinds #-}
-- {-# LANGUAGE PolyKinds #-}
-- {-# LANGUAGE TypeFamilies #-}
-- {-# LANGUAGE DeriveGeneric #-}
-- {-# LANGUAGE TypeOperators #-}
-- {-# LANGUAGE FlexibleInstances #-}
-- {-# LANGUAGE OverloadedStrings #-}
--
-- import Data.Proxy
-- import Data.Text
-- import Servant
--
-- -- our type for a Greeting message
-- data Greet = Greet { _msg :: Text }
-- deriving (Generic, Show)
--
-- -- we get our JSON serialization for free
-- instance FromJSON Greet
-- instance ToJSON Greet
--
-- -- we provide a sample value for the 'Greet' type
-- instance ToSample Greet where
-- toSample = Just g
--
-- where g = Greet "Hello, haskeller!"
--
-- instance ToParam (QueryParam "capital" Bool) where
-- toParam _ =
-- DocQueryParam "capital"
-- ["true", "false"]
-- "Get the greeting message in uppercase (true) or not (false). Default is false."
--
-- instance ToCapture (Capture "name" Text) where
-- toCapture _ = DocCapture "name" "name of the person to greet"
--
-- instance ToCapture (Capture "greetid" Text) where
-- toCapture _ = DocCapture "greetid" "identifier of the greet msg to remove"
--
-- -- API specification
-- type TestApi =
-- "hello" :> Capture "name" Text :> QueryParam "capital" Bool :> Get Greet
-- :<|> "greet" :> RQBody Greet :> Post Greet
-- :<|> "delete" :> Capture "greetid" Text :> Delete
--
-- testApi :: Proxy TestApi
-- testApi = Proxy
--
-- -- Generate the Documentation's ADT
-- greetDocs :: API
-- greetDocs = docs testApi
--
-- main :: IO ()
-- main = putStrLn $ markdown greetDocs
--
module Servant.Docs
-- | The class that abstracts away the impact of API combinators on
-- documentation generation.
class HasDocs layout
docsFor :: HasDocs layout => Proxy layout -> (Endpoint, Action) -> API
-- | Generate the docs for a given API that implements HasDocs.
docs :: HasDocs layout => Proxy layout -> API
-- | Generate documentation in Markdown format for the given API.
markdown :: API -> String
-- | The class that lets us display a sample JSON input or output when
-- generating documentation for endpoints that either:
--
--
-- {-# LANGUAGE DeriveGeneric #-}
-- {-# LANGUAGE OverloadedStrings #-}
--
-- import Data.Aeson
-- import Data.Text
-- import GHC.Generics
--
-- data Greet = Greet { _msg :: Text }
-- deriving (Generic, Show)
--
-- instance FromJSON Greet
-- instance ToJSON Greet
--
-- instance ToSample Greet where
-- toSample = Just g
--
-- where g = Greet "Hello, haskeller!"
--
--
-- You can also instantiate this class using toSamples instead of
-- toSample: it lets you specify different responses along with
-- some context (as Text) that explains when you're supposed to
-- get the corresponding response.
class ToJSON a => ToSample a where toSample = fmap snd $ listToMaybe samples where samples = toSamples :: [(Text, a)] toSamples = maybe [] (return . ("",)) s where s = toSample :: Maybe a
toSample :: ToSample a => Maybe a
toSamples :: ToSample a => [(Text, a)]
sampleByteString :: ToSample a => Proxy a -> Maybe ByteString
sampleByteStrings :: ToSample a => Proxy a -> [(Text, ByteString)]
-- | The class that helps us automatically get documentation for GET
-- parameters.
--
-- Example of an instance:
--
-- -- instance ToParam (QueryParam "capital" Bool) where -- toParam _ = -- DocQueryParam "capital" -- ["true", "false"] -- "Get the greeting message in uppercase (true) or not (false). Default is false." --class ToParam t toParam :: ToParam t => Proxy t -> DocQueryParam -- | The class that helps us automatically get documentation for URL -- captures. -- -- Example of an instance: -- --
-- instance ToCapture (Capture "name" Text) where -- toCapture _ = DocCapture "name" "name of the person to greet" --class ToCapture c toCapture :: ToCapture c => Proxy c -> DocCapture -- | Supported HTTP request methods data Method -- | the DELETE method DocDELETE :: Method -- | the GET method DocGET :: Method -- | the POST method DocPOST :: Method -- | the PUT method DocPUT :: Method -- | An Endpoint type that holds the path and the -- method. -- -- Gets used as the key in the API hashmap. Modify -- defEndpoint or any Endpoint value you want using the -- path and method lenses to tweak. -- --
-- λ> defEndpoint -- GET / -- λ> defEndpoint & path <>~ ["foo"] -- GET /foo -- λ> defEndpoint & path <>~ ["foo"] & method .~ DocPOST -- POST /foo --data Endpoint path :: Lens' Endpoint [String] method :: Lens' Endpoint Method -- | An Endpoint whose path is `"/"` and whose method is -- DocGET -- -- Here's how you can modify it: -- --
-- λ> defEndpoint -- GET / -- λ> defEndpoint & path <>~ ["foo"] -- GET /foo -- λ> defEndpoint & path <>~ ["foo"] & method .~ DocPOST -- POST /foo --defEndpoint :: Endpoint -- | Our API type, a good old hashmap from Endpoint to Action type API = HashMap Endpoint Action -- | An empty API emptyAPI :: API -- | A type to represent captures. Holds the name of the capture and a -- description. -- -- Write a ToCapture instance for your captured types. data DocCapture DocCapture :: String -> String -> DocCapture _capSymbol :: DocCapture -> String _capDesc :: DocCapture -> String capSymbol :: Lens' DocCapture String capDesc :: Lens' DocCapture String -- | A type to represent a GET parameter from the Query String. -- Holds its name, the possible values (leave empty if there isn't a -- finite number of them), and a description of how it influences the -- output or behavior. -- -- Write a ToParam instance for your GET parameter types data DocQueryParam DocQueryParam :: String -> [String] -> String -> ParamKind -> DocQueryParam _paramName :: DocQueryParam -> String _paramValues :: DocQueryParam -> [String] _paramDesc :: DocQueryParam -> String _paramKind :: DocQueryParam -> ParamKind -- | Type of GET parameter: -- --
-- λ> defResponse
-- Response {_respStatus = 200, _respBody = []}
-- λ> defResponse & respStatus .~ 204 & respBody .~ [("If everything goes well", "{ \"status\": \"ok\" }")]
-- Response {_respStatus = 204, _respBody = [("If everything goes well", "{ \"status\": \"ok\" }")]}
--
data Response
respStatus :: Lens' Response Int
respBody :: Lens' Response [(Text, ByteString)]
-- | Default response: status code 200, no response body.
--
-- Can be tweaked with two lenses.
--
--
-- λ> defResponse
-- Response {_respStatus = 200, _respBody = Nothing}
-- λ> defResponse & respStatus .~ 204 & respBody .~ Just "[]"
-- Response {_respStatus = 204, _respBody = Just "[]"}
--
defResponse :: Response
-- | A datatype that represents everything that can happen at an endpoint,
-- with its lenses:
--
--
--
-- You can tweak an Action (like the default defAction)
-- with these lenses to transform an action and add some information to
-- it.
data Action
captures :: Lens' Action [DocCapture]
headers :: Lens' Action [Text]
params :: Lens' Action [DocQueryParam]
rqbody :: Lens' Action (Maybe ByteString)
response :: Lens' Action Response
defAction :: Action
-- | Create an API that's comprised of a single endpoint. API is a
-- Monoid, so combine multiple endpoints with mappend or
-- <>.
single :: Endpoint -> Action -> API
instance (KnownSymbol path, HasDocs sublayout) => HasDocs (path :> sublayout)
instance (ToSample a, HasDocs sublayout) => HasDocs (ReqBody a :> sublayout)
instance HasDocs Raw
instance (KnownSymbol sym, ToParam (QueryFlag sym), HasDocs sublayout) => HasDocs (QueryFlag sym :> sublayout)
instance (KnownSymbol sym, ToParam (QueryParams sym a), HasDocs sublayout) => HasDocs (QueryParams sym a :> sublayout)
instance (KnownSymbol sym, ToParam (QueryParam sym a), HasDocs sublayout) => HasDocs (QueryParam sym a :> sublayout)
instance ToSample a => HasDocs (Put a)
instance ToSample a => HasDocs (Post a)
instance (KnownSymbol sym, HasDocs sublayout) => HasDocs (Header sym a :> sublayout)
instance ToSample a => HasDocs (Get a)
instance HasDocs Delete
instance (KnownSymbol sym, ToCapture (Capture sym a), HasDocs sublayout) => HasDocs (Capture sym a :> sublayout)
instance (HasDocs layout1, HasDocs layout2) => HasDocs (layout1 :<|> layout2)
instance Eq Method
instance Generic Method
instance Eq Endpoint
instance Generic Endpoint
instance Eq DocCapture
instance Show DocCapture
instance Eq ParamKind
instance Show ParamKind
instance Eq DocQueryParam
instance Show DocQueryParam
instance Eq Response
instance Show Response
instance Eq Action
instance Show Action
instance Datatype D1Method
instance Constructor C1_0Method
instance Constructor C1_1Method
instance Constructor C1_2Method
instance Constructor C1_3Method
instance Datatype D1Endpoint
instance Constructor C1_0Endpoint
instance Selector S1_0_0Endpoint
instance Selector S1_0_1Endpoint
instance Hashable Endpoint
instance Show Endpoint
instance Hashable Method
instance Show Method