@@ -32,6 +32,8 @@ import qualified Data.ByteString.Char8 as BSC
32import Data.ByteString.Lazy.Char8
32import Data.ByteString.Lazy.Char8
33 (ByteString)
33 (ByteString)
34import qualified Data.CaseInsensitive as CI
34import qualified Data.CaseInsensitive as CI
35import Data.Foldable
37import Data.Foldable
37import Data.Hashable
39import Data.Hashable
@@ -74,14 +76,15 @@ import qualified Network.HTTP.Types as HTTP
74-- or any 'Endpoint' value you want using the 'path' and 'method'
76-- or any 'Endpoint' value you want using the 'path' and 'method'
75-- lenses to tweak.
77-- lenses to tweak.
78−-- λ> 'defEndpoint'
79+-- >>> defEndpoint
80−-- λ> 'defEndpoint' & 'path' '<>~' ["foo"]
82+-- >>> defEndpoint & path <>~ ["foo"]
81−-- GET /foo
83+-- "GET" /foo
82−-- λ> 'defEndpoint' & 'path' '<>~' ["foo"] & 'method' '.~' 'HTTP.methodPost'
85+-- >>> defEndpoint & path <>~ ["foo"] & method .~ HTTP.methodPost
83−-- POST /foo
86+-- "POST" /foo
85data Endpoint = Endpoint
88data Endpoint = Endpoint
86 { _path :: [String] -- type collected
89 { _path :: [String] -- type collected
87 , _method :: HTTP.Method -- type collected
90 , _method :: HTTP.Method -- type collected
@@ -102,14 +105,15 @@ showPath ps = concatMap ('/' :) ps
103-- Here's how you can modify it:
106-- Here's how you can modify it:
106−-- λ> 'defEndpoint'
108+-- >>> defEndpoint
107−-- GET /
109+-- "GET" /
108−-- λ> 'defEndpoint' & 'path' '<>~' ["foo"]
111+-- >>> defEndpoint & path <>~ ["foo"]
109−-- GET /foo
112+-- "GET" /foo
110−-- λ> 'defEndpoint' & 'path' '<>~' ["foo"] & 'method' '.~' 'HTTP.methodPost'
114+-- >>> defEndpoint & path <>~ ["foo"] & method .~ HTTP.methodPost
111−-- POST /foo
115+-- "POST" /foo
113defEndpoint :: Endpoint
117defEndpoint :: Endpoint
114defEndpoint = Endpoint [] HTTP.methodGet
118defEndpoint = Endpoint [] HTTP.methodGet
@@ -220,12 +224,14 @@ data ParamKind = Normal | List | Flag
220-- want to write a 'ToSample' instance for the type that'll be represented
224-- want to write a 'ToSample' instance for the type that'll be represented
221-- as encoded data in the response.
225-- as encoded data in the response.
223−-- Can be tweaked with three lenses.
227+-- Can be tweaked with four lenses.
230+-- Response {_respStatus = 200, _respTypes = [], _respBody = [], _respHeaders = []}
232+-- >>> defResponse & respStatus .~ 204 & respBody .~ [("If everything goes well", "application/json", "{ \"status\": \"ok\" }")]
233+-- Response {_respStatus = 204, _respTypes = [], _respBody = [("If everything goes well",application/json,"{ \"status\": \"ok\" }")], _respHeaders = []}
226−-- > Response {_respStatus = 200, _respTypes = [], _respBody = []}
227−-- > λ> defResponse & respStatus .~ 204 & respBody .~ [("If everything goes well", "{ \"status\": \"ok\" }")]
228−-- > Response {_respStatus = 204, _respTypes = [], _respBody = [("If everything goes well", "{ \"status\": \"ok\" }")]}
229data Response = Response
235data Response = Response
230 { _respStatus :: Int
236 { _respStatus :: Int
231 , _respTypes :: [M.MediaType]
237 , _respTypes :: [M.MediaType]
@@ -235,12 +241,14 @@ data Response = Response
236-- | Default response: status code 200, no response body.
242-- | Default response: status code 200, no response body.
238−-- Can be tweaked with two lenses.
244+-- Can be tweaked with four lenses.
247+-- Response {_respStatus = 200, _respTypes = [], _respBody = [], _respHeaders = []}
249+-- >>> defResponse & respStatus .~ 204
250+-- Response {_respStatus = 204, _respTypes = [], _respBody = [], _respHeaders = []}
241−-- > Response {_respStatus = 200, _respBody = Nothing}
242−-- > λ> defResponse & respStatus .~ 204 & respBody .~ Just "[]"
243−-- > Response {_respStatus = 204, _respBody = Just "[]"}
244defResponse :: Response
252defResponse :: Response
245defResponse = Response
253defResponse = Response
246 { _respStatus = 200
254 { _respStatus = 200
@@ -286,10 +294,12 @@ Action a c h p n m ts body resp `combineAction` Action a' c' h' p' n' m' _ _ _ =
287-- Tweakable with lenses.
295-- Tweakable with lenses.
289−-- > λ> defAction
297+-- >>> defAction
290−-- > Action {_captures = [], _headers = [], _params = [], _mxParams = [], _rqbody = Nothing, _response = Response {_respStatus = 200, _respBody = Nothing}}
298+-- Action {_authInfo = [], _captures = [], _headers = [], _params = [], _notes = [], _mxParams = [], _rqtypes = [], _rqbody = [], _response = Response {_respStatus = 200, _respTypes = [], _respBody = [], _respHeaders = []}}
291−-- > λ> defAction & response.respStatus .~ 201
300+-- >>> defAction & response.respStatus .~ 201
292−-- > Action {_captures = [], _headers = [], _params = [], _mxParams = [], _rqbody = Nothing, _response = Response {_respStatus = 201, _respBody = Nothing}}
301+-- Action {_authInfo = [], _captures = [], _headers = [], _params = [], _notes = [], _mxParams = [], _rqtypes = [], _rqbody = [], _response = Response {_respStatus = 201, _respTypes = [], _respBody = [], _respHeaders = []}}
293defAction :: Action
303defAction :: Action
294defAction =
304defAction =
295 Action []
305 Action []
@@ -357,7 +367,8 @@ makeLenses ''RenderingOptions
357-- | Generate the docs for a given API that implements 'HasDocs'. This is the
367-- | Generate the docs for a given API that implements 'HasDocs'. This is the
358-- default way to create documentation.
368-- default way to create documentation.
360−-- prop> docs == docsWithOptions defaultDocOptions
370+-- > docs == docsWithOptions defaultDocOptions
361docs :: HasDocs api => Proxy api -> API
372docs :: HasDocs api => Proxy api -> API
362docs p = docsWithOptions p defaultDocOptions
373docs p = docsWithOptions p defaultDocOptions
@@ -958,7 +969,6 @@ instance (KnownSymbol desc, HasDocs api)
958-- both are even defined) for any particular type.
969-- both are even defined) for any particular type.
959instance (ToSample a, AllMimeRender (ct ': cts) a, HasDocs api)
970instance (ToSample a, AllMimeRender (ct ': cts) a, HasDocs api)
960 => HasDocs (ReqBody' mods (ct ': cts) a :> api) where
971 => HasDocs (ReqBody' mods (ct ': cts) a :> api) where
962 docsFor Proxy (endpoint, action) opts@DocOptions{..} =
972 docsFor Proxy (endpoint, action) opts@DocOptions{..} =
963 docsFor subApiP (endpoint, action') opts
973 docsFor subApiP (endpoint, action') opts
@@ -969,8 +979,17 @@ instance (ToSample a, AllMimeRender (ct ': cts) a, HasDocs api)
969 t = Proxy :: Proxy (ct ': cts)
979 t = Proxy :: Proxy (ct ': cts)
970 p = Proxy :: Proxy a
980 p = Proxy :: Proxy a
982+-- | TODO: this instance is incomplete.
972−instance HasDocs api => HasDocs (StreamBody framing ctype a :> api) where
983+instance (HasDocs api, Accept ctype) => HasDocs (StreamBody framing ctype a :> api) where
973− docsFor Proxy _ _ = error "HasDocs @StreamBody"
984+ docsFor Proxy (endpoint, action) opts =
985+ docsFor subApiP (endpoint, action') opts
987+ subApiP = Proxy :: Proxy api
990+ action' = action & rqtypes .~ toList (contentTypes t)
992+ t = Proxy :: Proxy ctype
975instance (KnownSymbol path, HasDocs api) => HasDocs (path :> api) where
994instance (KnownSymbol path, HasDocs api) => HasDocs (path :> api) where
@@ -1036,3 +1055,6 @@ instance ToSample a => ToSample (Product a)
1036instance ToSample a => ToSample (First a)
1055instance ToSample a => ToSample (First a)
1037instance ToSample a => ToSample (Last a)
1056instance ToSample a => ToSample (Last a)
1038instance ToSample a => ToSample (Dual a)
1057instance ToSample a => ToSample (Dual a)
1060+-- >>> :set -XOverloadedStrings