on type-errors help sign in
112 lines 4.1 kB history raw
1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE DeriveGeneric #-}
3{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE OverloadedStrings #-}
6{-# LANGUAGE TypeOperators #-}
7{-# OPTIONS_GHC -fno-warn-orphans #-}
8import Control.Lens
9import Data.Aeson
10import Data.Proxy
11import Data.String.Conversions
12import Data.Text
13 (Text)
14import GHC.Generics
15import Servant.API
16import Servant.Docs
18-- * Example
20-- | A greet message data type
21newtype Greet = Greet Text
22 deriving (Generic, Show)
24-- | We can get JSON support automatically. This will be used to parse
25-- and encode a Greeting as 'JSON'.
26instance FromJSON Greet
27instance ToJSON Greet
29-- | We can also implement 'MimeRender' for additional formats like 'PlainText'.
30instance MimeRender PlainText Greet where
31 mimeRender Proxy (Greet s) = "\"" <> cs s <> "\""
33-- We add some useful annotations to our captures,
34-- query parameters and request body to make the docs
35-- really helpful.
36instance ToCapture (Capture "name" Text) where
37 toCapture _ = DocCapture "name" "name of the person to greet"
39instance ToCapture (Capture "greetid" Text) where
40 toCapture _ = DocCapture "greetid" "identifier of the greet msg to remove"
42instance ToParam (QueryParam "capital" Bool) where
43 toParam _ =
44 DocQueryParam "capital"
45 ["true", "false"]
46 "Get the greeting message in uppercase (true) or not (false).\
47 \Default is false."
48 Normal
50instance ToSample Greet where
51 toSamples _ =
52 [ ("If you use ?capital=true", Greet "HELLO, HASKELLER")
53 , ("If you use ?capital=false", Greet "Hello, haskeller")
54 ]
56instance ToSample Int where
57 toSamples _ = singleSample 1729
59-- We define some introductory sections, these will appear at the top of the
60-- documentation.
61--
62-- We pass them in with 'docsWith', below. If you only want to add
63-- introductions, you may use 'docsWithIntros'
64intro1 :: DocIntro
65intro1 = DocIntro "On proper introductions." -- The title
66 [ "Hello there."
67 , "As documentation is usually written for humans, it's often useful \
68 \to introduce concepts with a few words." ] -- Elements are paragraphs
70intro2 :: DocIntro
71intro2 = DocIntro "This title is below the last"
72 [ "You'll also note that multiple intros are possible." ]
75-- API specification
76type TestApi =
77 -- GET /hello/:name?capital={true, false} returns a Greet as JSON or PlainText
78 "hello" :> Capture "name" Text :> Header "X-Num-Fairies" Int :> QueryParam "capital" Bool :> Get '[JSON, PlainText] Greet
80 -- POST /greet with a Greet as JSON in the request body,
81 -- returns a Greet as JSON
82 :<|> "greet" :> ReqBody '[JSON] Greet :> Post '[JSON] (Headers '[Header "X-Example" Int] Greet)
84 -- DELETE /greet/:greetid
85 :<|> "greet" :> Capture "greetid" Text :> Delete '[JSON] NoContent
87testApi :: Proxy TestApi
88testApi = Proxy
90-- Build some extra information for the DELETE /greet/:greetid endpoint. We
91-- want to add documentation about a secret unicorn header and some extra
92-- notes.
93extra :: ExtraInfo TestApi
94extra =
95 extraInfo (Proxy :: Proxy ("greet" :> Capture "greetid" Text :> Delete '[JSON] NoContent)) $
96 defAction & headers <>~ [("X-Num-Unicorns", "1")]
97 & notes <>~ [ DocNote "Title" ["This is some text"]
98 , DocNote "Second section" ["And some more"]
99 ]
101-- Generate the data that lets us have API docs. This
102-- is derived from the type as well as from
103-- the 'ToCapture', 'ToParam' and 'ToSample' instances from above.
104--
105-- If you didn't want intros and extra information, you could just call:
106--
107-- > docs testAPI :: API
108docsGreet :: API
109docsGreet = docsWith defaultDocOptions [intro1, intro2] extra testApi
111main :: IO ()
112main = putStrLn $ markdownWith (defRenderingOptions { _renderCurlBasePath = Just "http://localhost:80" }) docsGreet