-- 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. -- -- CHANGELOG @package servant-docs @version 0.4.4.7 module Servant.Docs.Internal -- | 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 Endpoint :: [String] -> Method -> Endpoint [_path] :: Endpoint -> [String] [_method] :: Endpoint -> Method -- | Render a path as a /-delimited string showPath :: [String] -> String -- | 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 documentation type, a product of top-level information and a -- good old hashmap from Endpoint to Action data API API :: [DocIntro] -> HashMap Endpoint Action -> API [_apiIntros] :: API -> [DocIntro] [_apiEndpoints] :: 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 -- | 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 -- | An introductory paragraph for your documentation. You can pass these -- to docsWithIntros. data DocIntro DocIntro :: String -> [String] -> DocIntro -- | Appears above the intro blob [_introTitle] :: DocIntro -> String -- | Each String is a paragraph. [_introBody] :: DocIntro -> [String] -- | A type to represent extra notes that may be attached to an -- Action. -- -- This is intended to be used when writing your own HasDocs instances to -- add extra sections to your endpoint's documentation. data DocNote DocNote :: String -> [String] -> DocNote [_noteTitle] :: DocNote -> String [_noteBody] :: DocNote -> [String] -- | Type of extra information that a user may wish to "union" with their -- documentation. -- -- These are intended to be built using extraInfo. Multiple ExtraInfo may -- be combined with the monoid instance. newtype ExtraInfo layout ExtraInfo :: (HashMap Endpoint Action) -> ExtraInfo layout -- | Type of GET parameter: -- -- data ParamKind Normal :: ParamKind List :: ParamKind Flag :: ParamKind -- | A type to represent an HTTP response. Has an Int status, a list -- of possible MediaTypes, and a list of example -- ByteString response bodies. Tweak defResponse using the -- respStatus, respTypes and respBody lenses if you -- want. -- -- If you want to respond with a non-empty response body, you'll most -- likely want to write a ToSample instance for the type that'll -- be represented as encoded data in the response. -- -- Can be tweaked with three lenses. -- --
--   λ> defResponse
--   Response {_respStatus = 200, _respTypes = [], _respBody = []}
--   λ> defResponse & respStatus .~ 204 & respBody .~ [("If everything goes well", "{ \"status\": \"ok\" }")]
--   Response {_respStatus = 204, _respTypes = [], _respBody = [("If everything goes well", "{ \"status\": \"ok\" }")]}
--   
data Response Response :: Int -> [MediaType] -> [(Text, MediaType, ByteString)] -> [Header] -> Response [_respStatus] :: Response -> Int [_respTypes] :: Response -> [MediaType] [_respBody] :: Response -> [(Text, MediaType, ByteString)] [_respHeaders] :: Response -> [Header] -- | 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 Action :: [DocCapture] -> [Text] -> [DocQueryParam] -> [DocNote] -> [(String, [DocQueryParam])] -> [MediaType] -> [(MediaType, ByteString)] -> Response -> Action [_captures] :: Action -> [DocCapture] [_headers] :: Action -> [Text] [_params] :: Action -> [DocQueryParam] [_notes] :: Action -> [DocNote] [_mxParams] :: Action -> [(String, [DocQueryParam])] [_rqtypes] :: Action -> [MediaType] [_rqbody] :: Action -> [(MediaType, ByteString)] [_response] :: Action -> Response -- | Combine two Actions, we can't make a monoid as merging Response breaks -- the laws. -- -- As such, we invent a non-commutative, left associative operation -- combineAction to mush two together taking the response, body -- and content types from the very left. combineAction :: Action -> Action -> Action 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 apiIntros :: Lens' API [DocIntro] apiEndpoints :: Lens' API (HashMap Endpoint Action) path :: Lens' Endpoint [String] method :: Lens' Endpoint Method capSymbol :: Lens' DocCapture String capDesc :: Lens' DocCapture String paramValues :: Lens' DocQueryParam [String] paramName :: Lens' DocQueryParam String paramKind :: Lens' DocQueryParam ParamKind paramDesc :: Lens' DocQueryParam String introTitle :: Lens' DocIntro String introBody :: Lens' DocIntro [String] noteTitle :: Lens' DocNote String noteBody :: Lens' DocNote [String] respTypes :: Lens' Response [MediaType] respStatus :: Lens' Response Int respHeaders :: Lens' Response [Header] respBody :: Lens' Response [(Text, MediaType, ByteString)] rqtypes :: Lens' Action [MediaType] rqbody :: Lens' Action [(MediaType, ByteString)] response :: Lens' Action Response params :: Lens' Action [DocQueryParam] notes :: Lens' Action [DocNote] mxParams :: Lens' Action [(String, [DocQueryParam])] headers :: Lens' Action [Text] captures :: Lens' Action [DocCapture] -- | Generate the docs for a given API that implements HasDocs. This -- is the default way to create documentation. docs :: HasDocs layout => Proxy layout -> API -- | Closed type family, check if endpoint is exactly within API. -- | Create an ExtraInfo that is garunteed to be within the given -- API layout. -- -- The safety here is to ensure that you only add custom documentation to -- an endpoint that actually exists within your API. -- --
--   extra :: ExtraInfo TestApi
--   extra =
--       extraInfo (Proxy :: Proxy ("greet" :> Capture "greetid" Text :> Delete)) $
--                defAction & headers <>~ ["unicorns"]
--                          & notes   <>~ [ DocNote "Title" ["This is some text"]
--                                        , DocNote "Second secton" ["And some more"]
--                                        ]
--   
extraInfo :: (IsIn endpoint layout, HasLink endpoint, HasDocs endpoint) => Proxy endpoint -> Action -> ExtraInfo layout -- | Generate documentation given some extra introductions (in the form of -- DocInfo) and some extra endpoint documentation (in the form -- of ExtraInfo. -- -- The extra introductions will be prepended to the top of the -- documentation, before the specific endpoint documentation. The extra -- endpoint documentation will be "unioned" with the automatically -- generated endpoint documentation. -- -- You are expected to build up the ExtraInfo with the Monoid instance -- and extraInfo. -- -- If you only want to add an introduction, use docsWithIntros. docsWith :: HasDocs layout => [DocIntro] -> ExtraInfo layout -> Proxy layout -> API -- | Generate the docs for a given API that implements HasDocs with -- with any number of introduction(s) docsWithIntros :: HasDocs layout => [DocIntro] -> Proxy layout -> API -- | The class that abstracts away the impact of API combinators on -- documentation generation. class HasDocs layout docsFor :: HasDocs layout => Proxy layout -> (Endpoint, Action) -> API -- | The class that lets us display a sample input or output in the -- supported content-types when generating documentation for endpoints -- that either: -- -- -- -- Example of an instance: -- --
--   {-# 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 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 ToSample a b | a -> b where toSample _ = snd <$> listToMaybe samples where samples = toSamples (Proxy :: Proxy a) toSamples _ = maybe [] (return . ("",)) s where s = toSample (Proxy :: Proxy a) toSample :: ToSample a b => Proxy a -> Maybe b toSamples :: ToSample a b => Proxy a -> [(Text, b)] class AllHeaderSamples ls allHeaderToSample :: AllHeaderSamples ls => Proxy ls -> [Header] -- | Synthesise a sample value of a type, encoded in the specified media -- types. sampleByteString :: (ToSample a b, IsNonEmpty ctypes, AllMimeRender ctypes b) => Proxy ctypes -> Proxy a -> [(MediaType, ByteString)] -- | Synthesise a list of sample values of a particular type, encoded in -- the specified media types. sampleByteStrings :: (ToSample a b, IsNonEmpty ctypes, AllMimeRender ctypes b) => Proxy ctypes -> Proxy a -> [(Text, MediaType, ByteString)] -- | Generate a list of MediaType values describing the content -- types accepted by an API component. class SupportedTypes (list :: [*]) supportedTypes :: SupportedTypes list => Proxy list -> [MediaType] -- | 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 -- | Generate documentation in Markdown format for the given API. markdown :: API -> String -- | The generated docs for a :<|> b just appends the -- docs for a with the docs for b. -- | "books" :> Capture "isbn" Text will appear as -- books:isbn in the docs. instance Servant.Docs.Internal.ToSample a b => Servant.Docs.Internal.ToSample (Servant.API.ResponseHeaders.Headers ls a) b instance Servant.Docs.Internal.AllHeaderSamples '[] instance (Data.ByteString.Conversion.To.ToByteString l, Servant.Docs.Internal.AllHeaderSamples ls, Servant.Docs.Internal.ToSample l l, GHC.TypeLits.KnownSymbol h) => Servant.Docs.Internal.AllHeaderSamples (Servant.API.Header.Header h l : ls) instance Servant.Docs.Internal.SupportedTypes '[] instance (Servant.API.ContentTypes.Accept ctype, Servant.Docs.Internal.SupportedTypes rest) => Servant.Docs.Internal.SupportedTypes (ctype : rest) instance (Servant.Docs.Internal.HasDocs layout1, Servant.Docs.Internal.HasDocs layout2) => Servant.Docs.Internal.HasDocs (layout1 Servant.API.Alternative.:<|> layout2) instance forall (k :: BOX) (k1 :: BOX) (sym :: GHC.TypeLits.Symbol) (a :: k1) (sublayout :: k). (GHC.TypeLits.KnownSymbol sym, Servant.Docs.Internal.ToCapture (Servant.API.Capture.Capture sym a), Servant.Docs.Internal.HasDocs sublayout) => Servant.Docs.Internal.HasDocs (Servant.API.Capture.Capture sym a Servant.API.Sub.:> sublayout) instance (Servant.Docs.Internal.ToSample a b, Servant.API.ContentTypes.IsNonEmpty cts, Servant.API.ContentTypes.AllMimeRender cts b, Servant.Docs.Internal.SupportedTypes cts) => Servant.Docs.Internal.HasDocs (Servant.API.Delete.Delete cts a) instance (Servant.Docs.Internal.ToSample a b, Servant.API.ContentTypes.IsNonEmpty cts, Servant.API.ContentTypes.AllMimeRender cts b, Servant.Docs.Internal.SupportedTypes cts, Servant.Docs.Internal.AllHeaderSamples ls, Servant.API.ResponseHeaders.GetHeaders (Servant.API.ResponseHeaders.HList ls)) => Servant.Docs.Internal.HasDocs (Servant.API.Delete.Delete cts (Servant.API.ResponseHeaders.Headers ls a)) instance (Servant.Docs.Internal.ToSample a b, Servant.API.ContentTypes.IsNonEmpty cts, Servant.API.ContentTypes.AllMimeRender cts b, Servant.Docs.Internal.SupportedTypes cts) => Servant.Docs.Internal.HasDocs (Servant.API.Get.Get cts a) instance (Servant.Docs.Internal.ToSample a b, Servant.API.ContentTypes.IsNonEmpty cts, Servant.API.ContentTypes.AllMimeRender cts b, Servant.Docs.Internal.SupportedTypes cts, Servant.Docs.Internal.AllHeaderSamples ls, Servant.API.ResponseHeaders.GetHeaders (Servant.API.ResponseHeaders.HList ls)) => Servant.Docs.Internal.HasDocs (Servant.API.Get.Get cts (Servant.API.ResponseHeaders.Headers ls a)) instance forall (k :: BOX) (sym :: GHC.TypeLits.Symbol) a (sublayout :: k). (GHC.TypeLits.KnownSymbol sym, Servant.Docs.Internal.HasDocs sublayout) => Servant.Docs.Internal.HasDocs (Servant.API.Header.Header sym a Servant.API.Sub.:> sublayout) instance (Servant.Docs.Internal.ToSample a b, Servant.API.ContentTypes.IsNonEmpty cts, Servant.API.ContentTypes.AllMimeRender cts b, Servant.Docs.Internal.SupportedTypes cts) => Servant.Docs.Internal.HasDocs (Servant.API.Post.Post cts a) instance (Servant.Docs.Internal.ToSample a b, Servant.API.ContentTypes.IsNonEmpty cts, Servant.API.ContentTypes.AllMimeRender cts b, Servant.Docs.Internal.SupportedTypes cts, Servant.Docs.Internal.AllHeaderSamples ls, Servant.API.ResponseHeaders.GetHeaders (Servant.API.ResponseHeaders.HList ls)) => Servant.Docs.Internal.HasDocs (Servant.API.Post.Post cts (Servant.API.ResponseHeaders.Headers ls a)) instance (Servant.Docs.Internal.ToSample a b, Servant.API.ContentTypes.IsNonEmpty cts, Servant.API.ContentTypes.AllMimeRender cts b, Servant.Docs.Internal.SupportedTypes cts) => Servant.Docs.Internal.HasDocs (Servant.API.Put.Put cts a) instance (Servant.Docs.Internal.ToSample a b, Servant.API.ContentTypes.IsNonEmpty cts, Servant.API.ContentTypes.AllMimeRender cts b, Servant.Docs.Internal.SupportedTypes cts, Servant.Docs.Internal.AllHeaderSamples ls, Servant.API.ResponseHeaders.GetHeaders (Servant.API.ResponseHeaders.HList ls)) => Servant.Docs.Internal.HasDocs (Servant.API.Put.Put cts (Servant.API.ResponseHeaders.Headers ls a)) instance forall (k :: BOX) (k1 :: BOX) (sym :: GHC.TypeLits.Symbol) (a :: k1) (sublayout :: k). (GHC.TypeLits.KnownSymbol sym, Servant.Docs.Internal.ToParam (Servant.API.QueryParam.QueryParam sym a), Servant.Docs.Internal.HasDocs sublayout) => Servant.Docs.Internal.HasDocs (Servant.API.QueryParam.QueryParam sym a Servant.API.Sub.:> sublayout) instance forall (k :: BOX) (k1 :: BOX) (sym :: GHC.TypeLits.Symbol) (a :: k1) (sublayout :: k). (GHC.TypeLits.KnownSymbol sym, Servant.Docs.Internal.ToParam (Servant.API.QueryParam.QueryParams sym a), Servant.Docs.Internal.HasDocs sublayout) => Servant.Docs.Internal.HasDocs (Servant.API.QueryParam.QueryParams sym a Servant.API.Sub.:> sublayout) instance forall (k :: BOX) (sym :: GHC.TypeLits.Symbol) (sublayout :: k). (GHC.TypeLits.KnownSymbol sym, Servant.Docs.Internal.ToParam (Servant.API.QueryParam.QueryFlag sym), Servant.Docs.Internal.HasDocs sublayout) => Servant.Docs.Internal.HasDocs (Servant.API.QueryParam.QueryFlag sym Servant.API.Sub.:> sublayout) instance forall (k :: BOX) (k1 :: BOX) (sym :: GHC.TypeLits.Symbol) (a :: k1) (sublayout :: k). (GHC.TypeLits.KnownSymbol sym, Servant.Docs.Internal.ToParam (Servant.API.MatrixParam.MatrixParam sym a), Servant.Docs.Internal.HasDocs sublayout) => Servant.Docs.Internal.HasDocs (Servant.API.MatrixParam.MatrixParam sym a Servant.API.Sub.:> sublayout) instance forall (k :: BOX) (k1 :: BOX) (sym :: GHC.TypeLits.Symbol) (a :: k1) (sublayout :: k). (GHC.TypeLits.KnownSymbol sym, Servant.Docs.Internal.HasDocs sublayout) => Servant.Docs.Internal.HasDocs (Servant.API.MatrixParam.MatrixParams sym a Servant.API.Sub.:> sublayout) instance forall (k :: BOX) (sym :: GHC.TypeLits.Symbol) (sublayout :: k). (GHC.TypeLits.KnownSymbol sym, Servant.Docs.Internal.HasDocs sublayout) => Servant.Docs.Internal.HasDocs (Servant.API.MatrixParam.MatrixFlag sym Servant.API.Sub.:> sublayout) instance Servant.Docs.Internal.HasDocs Servant.API.Raw.Raw instance forall (k :: BOX) (k1 :: BOX) (cts :: [*]) (a :: k1) (sublayout :: k) b. (Servant.Docs.Internal.ToSample a b, Servant.API.ContentTypes.IsNonEmpty cts, Servant.API.ContentTypes.AllMimeRender cts b, Servant.Docs.Internal.HasDocs sublayout, Servant.Docs.Internal.SupportedTypes cts) => Servant.Docs.Internal.HasDocs (Servant.API.ReqBody.ReqBody cts a Servant.API.Sub.:> sublayout) instance forall (k :: BOX) (path :: GHC.TypeLits.Symbol) (sublayout :: k). (GHC.TypeLits.KnownSymbol path, Servant.Docs.Internal.HasDocs sublayout) => Servant.Docs.Internal.HasDocs (path Servant.API.Sub.:> sublayout) instance GHC.Generics.Selector Servant.Docs.Internal.S1_0_1Endpoint instance GHC.Generics.Selector Servant.Docs.Internal.S1_0_0Endpoint instance GHC.Generics.Constructor Servant.Docs.Internal.C1_0Endpoint instance GHC.Generics.Datatype Servant.Docs.Internal.D1Endpoint instance GHC.Generics.Constructor Servant.Docs.Internal.C1_3Method instance GHC.Generics.Constructor Servant.Docs.Internal.C1_2Method instance GHC.Generics.Constructor Servant.Docs.Internal.C1_1Method instance GHC.Generics.Constructor Servant.Docs.Internal.C1_0Method instance GHC.Generics.Datatype Servant.Docs.Internal.D1Method instance GHC.Show.Show Servant.Docs.Internal.API instance GHC.Classes.Eq Servant.Docs.Internal.API instance GHC.Show.Show Servant.Docs.Internal.Action instance GHC.Classes.Ord Servant.Docs.Internal.Action instance GHC.Classes.Eq Servant.Docs.Internal.Action instance GHC.Show.Show Servant.Docs.Internal.Response instance GHC.Classes.Ord Servant.Docs.Internal.Response instance GHC.Classes.Eq Servant.Docs.Internal.Response instance GHC.Show.Show Servant.Docs.Internal.DocQueryParam instance GHC.Classes.Ord Servant.Docs.Internal.DocQueryParam instance GHC.Classes.Eq Servant.Docs.Internal.DocQueryParam instance GHC.Show.Show Servant.Docs.Internal.ParamKind instance GHC.Classes.Ord Servant.Docs.Internal.ParamKind instance GHC.Classes.Eq Servant.Docs.Internal.ParamKind instance GHC.Show.Show Servant.Docs.Internal.DocNote instance GHC.Classes.Ord Servant.Docs.Internal.DocNote instance GHC.Classes.Eq Servant.Docs.Internal.DocNote instance GHC.Show.Show Servant.Docs.Internal.DocIntro instance GHC.Classes.Eq Servant.Docs.Internal.DocIntro instance GHC.Show.Show Servant.Docs.Internal.DocCapture instance GHC.Classes.Ord Servant.Docs.Internal.DocCapture instance GHC.Classes.Eq Servant.Docs.Internal.DocCapture instance GHC.Generics.Generic Servant.Docs.Internal.Endpoint instance GHC.Classes.Ord Servant.Docs.Internal.Endpoint instance GHC.Classes.Eq Servant.Docs.Internal.Endpoint instance GHC.Generics.Generic Servant.Docs.Internal.Method instance GHC.Classes.Ord Servant.Docs.Internal.Method instance GHC.Classes.Eq Servant.Docs.Internal.Method instance GHC.Show.Show Servant.Docs.Internal.Method instance Data.Hashable.Class.Hashable Servant.Docs.Internal.Method instance GHC.Show.Show Servant.Docs.Internal.Endpoint instance Data.Hashable.Class.Hashable Servant.Docs.Internal.Endpoint instance GHC.Base.Monoid Servant.Docs.Internal.API instance GHC.Classes.Ord Servant.Docs.Internal.DocIntro instance forall (k :: BOX) (a :: k). GHC.Base.Monoid (Servant.Docs.Internal.ExtraInfo a) -- | This module lets you get API docs for free. It lets you generate an -- API from the type that represents your API using docs: -- --
--   docs :: HasDocs api => Proxy api -> API
--   
-- -- Alternatively, if you wish to add one or more introductions to your -- documentation, use docsWithIntros: -- --
--   docsWithIntros :: HasDocs api => [DocIntro] -> Proxy api -> API
--   
-- -- You can then call markdown on the API value: -- --
--   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 is a complete example that you can run to see the markdown pretty -- printer in action: -- --
--   {-# LANGUAGE DataKinds             #-}
--   {-# LANGUAGE DeriveGeneric         #-}
--   {-# LANGUAGE FlexibleInstances     #-}
--   {-# LANGUAGE MultiParamTypeClasses #-}
--   {-# LANGUAGE OverloadedStrings     #-}
--   {-# LANGUAGE TypeOperators         #-}
--   {-# OPTIONS_GHC -fno-warn-orphans #-}
--   import Control.Lens
--   import Data.Aeson
--   import Data.Proxy
--   import Data.String.Conversions
--   import Data.Text (Text)
--   import GHC.Generics
--   import Servant.API
--   import Servant.Docs
--   
--   -- * Example
--   
--   -- | A greet message data type
--   newtype Greet = Greet Text
--     deriving (Generic, Show)
--   
--   -- | We can get JSON support automatically. This will be used to parse
--   -- and encode a Greeting as 'JSON'.
--   instance FromJSON Greet
--   instance ToJSON Greet
--   
--   -- | We can also implement 'MimeRender' for additional formats like 'PlainText'.
--   instance MimeRender PlainText Greet where
--       mimeRender Proxy (Greet s) = "\"" <> cs s <> "\""
--   
--   -- 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"
--   
--   instance ToCapture (Capture "greetid" Text) where
--     toCapture _ = DocCapture "greetid" "identifier of the greet msg to remove"
--   
--   instance ToParam (QueryParam "capital" Bool) where
--     toParam _ =
--       DocQueryParam "capital"
--                     ["true", "false"]
--                     "Get the greeting message in uppercase (true) or not (false).\
--                     \Default is false."
--                     Normal
--   
--   instance ToParam (MatrixParam "lang" String) where
--     toParam _ =
--       DocQueryParam "lang"
--                     ["en", "sv", "fr"]
--                     "Get the greeting message selected language. Default is en."
--                     Normal
--   
--   instance ToSample Greet Greet where
--     toSample _ = Just $ Greet "Hello, haskeller!"
--   
--     toSamples _ =
--       [ ("If you use ?capital=true", Greet "HELLO, HASKELLER")
--       , ("If you use ?capital=false", Greet "Hello, haskeller")
--       ]
--   
--   -- 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'
--   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." ]
--   
--   
--   -- API specification
--   type TestApi =
--          -- 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
--   
--          -- POST /greet with a Greet as JSON in the request body,
--          --             returns a Greet as JSON
--     :<|> "greet" :> ReqBody '[JSON] Greet :> Post '[JSON] Greet
--   
--          -- DELETE /greet/:greetid
--     :<|> "greet" :> Capture "greetid" Text :> Delete '[JSON] ()
--   
--   testApi :: Proxy TestApi
--   testApi = Proxy
--   
--   -- 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 =
--       extraInfo (Proxy :: Proxy ("greet" :> Capture "greetid" Text :> Delete '[JSON] ())) $
--                defAction & headers <>~ ["unicorns"]
--                          & notes   <>~ [ DocNote "Title" ["This is some text"]
--                                        , DocNote "Second secton" ["And some more"]
--                                        ]
--   
--   -- 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.
--   --
--   -- If you didn't want intros and extra information, you could just call:
--   --
--   -- > docs testAPI :: API
--   docsGreet :: API
--   docsGreet = docsWith [intro1, intro2] extra testApi
--   
--   main :: IO ()
--   main = putStrLn $ markdown docsGreet
--   
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. This -- is the default way to create documentation. docs :: HasDocs layout => Proxy layout -> API -- | Generate documentation in Markdown format for the given API. markdown :: API -> String -- | Type of extra information that a user may wish to "union" with their -- documentation. -- -- These are intended to be built using extraInfo. Multiple ExtraInfo may -- be combined with the monoid instance. newtype ExtraInfo layout ExtraInfo :: (HashMap Endpoint Action) -> ExtraInfo layout -- | Generate documentation given some extra introductions (in the form of -- DocInfo) and some extra endpoint documentation (in the form -- of ExtraInfo. -- -- The extra introductions will be prepended to the top of the -- documentation, before the specific endpoint documentation. The extra -- endpoint documentation will be "unioned" with the automatically -- generated endpoint documentation. -- -- You are expected to build up the ExtraInfo with the Monoid instance -- and extraInfo. -- -- If you only want to add an introduction, use docsWithIntros. docsWith :: HasDocs layout => [DocIntro] -> ExtraInfo layout -> Proxy layout -> API -- | Generate the docs for a given API that implements HasDocs with -- with any number of introduction(s) docsWithIntros :: HasDocs layout => [DocIntro] -> Proxy layout -> API -- | Create an ExtraInfo that is garunteed to be within the given -- API layout. -- -- The safety here is to ensure that you only add custom documentation to -- an endpoint that actually exists within your API. -- --
--   extra :: ExtraInfo TestApi
--   extra =
--       extraInfo (Proxy :: Proxy ("greet" :> Capture "greetid" Text :> Delete)) $
--                defAction & headers <>~ ["unicorns"]
--                          & notes   <>~ [ DocNote "Title" ["This is some text"]
--                                        , DocNote "Second secton" ["And some more"]
--                                        ]
--   
extraInfo :: (IsIn endpoint layout, HasLink endpoint, HasDocs endpoint) => Proxy endpoint -> Action -> ExtraInfo layout -- | The class that lets us display a sample input or output in the -- supported content-types when generating documentation for endpoints -- that either: -- -- -- -- Example of an instance: -- --
--   {-# 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 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 ToSample a b | a -> b where toSample _ = snd <$> listToMaybe samples where samples = toSamples (Proxy :: Proxy a) toSamples _ = maybe [] (return . ("",)) s where s = toSample (Proxy :: Proxy a) toSample :: ToSample a b => Proxy a -> Maybe b toSamples :: ToSample a b => Proxy a -> [(Text, b)] -- | Synthesise a sample value of a type, encoded in the specified media -- types. sampleByteString :: (ToSample a b, IsNonEmpty ctypes, AllMimeRender ctypes b) => Proxy ctypes -> Proxy a -> [(MediaType, ByteString)] -- | Synthesise a list of sample values of a particular type, encoded in -- the specified media types. sampleByteStrings :: (ToSample a b, IsNonEmpty ctypes, AllMimeRender ctypes b) => Proxy ctypes -> Proxy a -> [(Text, MediaType, 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 documentation type, a product of top-level information and a -- good old hashmap from Endpoint to Action data API apiIntros :: Lens' API [DocIntro] apiEndpoints :: Lens' 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: -- -- data ParamKind Normal :: ParamKind List :: ParamKind Flag :: ParamKind paramName :: Lens' DocQueryParam String paramValues :: Lens' DocQueryParam [String] paramDesc :: Lens' DocQueryParam String paramKind :: Lens' DocQueryParam ParamKind -- | A type to represent extra notes that may be attached to an -- Action. -- -- This is intended to be used when writing your own HasDocs instances to -- add extra sections to your endpoint's documentation. data DocNote DocNote :: String -> [String] -> DocNote [_noteTitle] :: DocNote -> String [_noteBody] :: DocNote -> [String] noteTitle :: Lens' DocNote String noteBody :: Lens' DocNote [String] -- | An introductory paragraph for your documentation. You can pass these -- to docsWithIntros. data DocIntro DocIntro :: String -> [String] -> DocIntro -- | Appears above the intro blob [_introTitle] :: DocIntro -> String -- | Each String is a paragraph. [_introBody] :: DocIntro -> [String] introTitle :: Lens' DocIntro String introBody :: Lens' DocIntro [String] -- | A type to represent an HTTP response. Has an Int status, a list -- of possible MediaTypes, and a list of example -- ByteString response bodies. Tweak defResponse using the -- respStatus, respTypes and respBody lenses if you -- want. -- -- If you want to respond with a non-empty response body, you'll most -- likely want to write a ToSample instance for the type that'll -- be represented as encoded data in the response. -- -- Can be tweaked with three lenses. -- --
--   λ> defResponse
--   Response {_respStatus = 200, _respTypes = [], _respBody = []}
--   λ> defResponse & respStatus .~ 204 & respBody .~ [("If everything goes well", "{ \"status\": \"ok\" }")]
--   Response {_respStatus = 204, _respTypes = [], _respBody = [("If everything goes well", "{ \"status\": \"ok\" }")]}
--   
data Response Response :: Int -> [MediaType] -> [(Text, MediaType, ByteString)] -> [Header] -> Response [_respStatus] :: Response -> Int [_respTypes] :: Response -> [MediaType] [_respBody] :: Response -> [(Text, MediaType, ByteString)] [_respHeaders] :: Response -> [Header] respStatus :: Lens' Response Int respTypes :: Lens' Response [MediaType] respBody :: Lens' Response [(Text, MediaType, 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] notes :: Lens' Action [DocNote] params :: Lens' Action [DocQueryParam] rqtypes :: Lens' Action [MediaType] rqbody :: Lens' Action [(MediaType, 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