on master help sign in
Merge pull request #767 from fierce-katie/docs-combinators
50be3a2Oleg Grenrus
servant-client/src/Servant/Client.hs+12
@@ -263,6 +263,18 @@ instance HasClient api
263 clientWithRoute Proxy =
263 clientWithRoute Proxy =
264 clientWithRoute (Proxy :: Proxy api)
264 clientWithRoute (Proxy :: Proxy api)
265
265
266+-- | Ignore @'Summary'@ in client functions.
267+instance HasClient api => HasClient (Summary desc :> api) where
268+ type Client (Summary desc :> api) = Client api
269+
270+ clientWithRoute _ = clientWithRoute (Proxy :: Proxy api)
271+
272+-- | Ignore @'Description'@ in client functions.
273+instance HasClient api => HasClient (Description desc :> api) where
274+ type Client (Description desc :> api) = Client api
275+
276+ clientWithRoute _ = clientWithRoute (Proxy :: Proxy api)
277+
266-- | If you use a 'QueryParam' in one of your endpoints in your API,
278-- | If you use a 'QueryParam' in one of your endpoints in your API,
267-- the corresponding querying function will automatically take
279-- the corresponding querying function will automatically take
268-- an additional argument of the type specified by your 'QueryParam',
280-- an additional argument of the type specified by your 'QueryParam',
servant-docs/src/Servant/Docs/Internal.hs+21
@@ -807,6 +807,27 @@ instance HasDocs Raw where
807 docsFor _proxy (endpoint, action) _ =
807 docsFor _proxy (endpoint, action) _ =
808 single endpoint action
808 single endpoint action
809
809
810+
811+instance (KnownSymbol desc, HasDocs api)
812+ => HasDocs (Description desc :> api) where
813+
814+ docsFor Proxy (endpoint, action) =
815+ docsFor subApiP (endpoint, action')
816+
817+ where subApiP = Proxy :: Proxy api
818+ action' = over notes (|> note) action
819+ note = DocNote (symbolVal (Proxy :: Proxy desc)) []
820+
821+instance (KnownSymbol desc, HasDocs api)
822+ => HasDocs (Summary desc :> api) where
823+
824+ docsFor Proxy (endpoint, action) =
825+ docsFor subApiP (endpoint, action')
826+
827+ where subApiP = Proxy :: Proxy api
828+ action' = over notes (|> note) action
829+ note = DocNote (symbolVal (Proxy :: Proxy desc)) []
830+
810-- TODO: We use 'AllMimeRender' here because we need to be able to show the
831-- TODO: We use 'AllMimeRender' here because we need to be able to show the
811-- example data. However, there's no reason to believe that the instances of
832-- example data. However, there's no reason to believe that the instances of
812-- 'AllMimeUnrender' and 'AllMimeRender' actually agree (or to suppose that
833-- 'AllMimeUnrender' and 'AllMimeRender' actually agree (or to suppose that
servant-docs/test/Servant/DocsSpec.hs+7
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE DeriveGeneric #-}
3{-# LANGUAGE DeriveGeneric #-}
3{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE FlexibleContexts #-}
@@ -7,6 +8,12 @@
7{-# LANGUAGE TypeOperators #-}
8{-# LANGUAGE TypeOperators #-}
8{-# LANGUAGE TypeSynonymInstances #-}
9{-# LANGUAGE TypeSynonymInstances #-}
9{-# OPTIONS_GHC -fno-warn-orphans #-}
10{-# OPTIONS_GHC -fno-warn-orphans #-}
11+#if __GLASGOW_HASKELL__ >= 800
12+{-# OPTIONS_GHC -freduction-depth=100 #-}
13+#else
14+{-# OPTIONS_GHC -fcontext-stack=100 #-}
15+#endif
16+
10module Servant.DocsSpec where
17module Servant.DocsSpec where
11
18
12import Control.Lens
19import Control.Lens
servant-foreign/src/Servant/Foreign/Internal.hs+14
@@ -350,6 +350,20 @@ instance HasForeign lang ftype api
350 foreignFor lang ftype Proxy req =
350 foreignFor lang ftype Proxy req =
351 foreignFor lang ftype (Proxy :: Proxy api) req
351 foreignFor lang ftype (Proxy :: Proxy api) req
352
352
353+instance HasForeign lang ftype api
354+ => HasForeign lang ftype (Summary desc :> api) where
355+ type Foreign ftype (Summary desc :> api) = Foreign ftype api
356+
357+ foreignFor lang ftype Proxy req =
358+ foreignFor lang ftype (Proxy :: Proxy api) req
359+
360+instance HasForeign lang ftype api
361+ => HasForeign lang ftype (Description desc :> api) where
362+ type Foreign ftype (Description desc :> api) = Foreign ftype api
363+
364+ foreignFor lang ftype Proxy req =
365+ foreignFor lang ftype (Proxy :: Proxy api) req
366+
353-- | Utility class used by 'listFromAPI' which computes
367-- | Utility class used by 'listFromAPI' which computes
354-- the data needed to generate a function for each endpoint
368-- the data needed to generate a function for each endpoint
355-- and hands it all back in a list.
369-- and hands it all back in a list.
servant-server/src/Servant/Server/Internal.hs+14−1
@@ -58,7 +58,8 @@ import Servant.API ((:<|>) (..), (:>), BasicAuth, Capt
58 IsSecure(..), Header, QueryFlag,
58 IsSecure(..), Header, QueryFlag,
59 QueryParam, QueryParams, Raw,
59 QueryParam, QueryParams, Raw,
60 RemoteHost, ReqBody, Vault,
60 RemoteHost, ReqBody, Vault,
61− WithNamedContext)
61+ WithNamedContext,
62+ Description, Summary)
62import Servant.API.ContentTypes (AcceptHeader (..),
63import Servant.API.ContentTypes (AcceptHeader (..),
63 AllCTRender (..),
64 AllCTRender (..),
64 AllCTUnrender (..),
65 AllCTUnrender (..),
@@ -533,6 +534,18 @@ instance HasServer api context => HasServer (HttpVersion :> api) context where
533 route Proxy context subserver =
534 route Proxy context subserver =
534 route (Proxy :: Proxy api) context (passToServer subserver httpVersion)
535 route (Proxy :: Proxy api) context (passToServer subserver httpVersion)
535
536
537+-- | Ignore @'Summary'@ in server handlers.
538+instance HasServer api ctx => HasServer (Summary desc :> api) ctx where
539+ type ServerT (Summary desc :> api) m = ServerT api m
540+
541+ route _ = route (Proxy :: Proxy api)
542+
543+-- | Ignore @'Description'@ in server handlers.
544+instance HasServer api ctx => HasServer (Description desc :> api) ctx where
545+ type ServerT (Description desc :> api) m = ServerT api m
546+
547+ route _ = route (Proxy :: Proxy api)
548+
536-- | Singleton type representing a server that serves an empty API.
549-- | Singleton type representing a server that serves an empty API.
537data EmptyServer = EmptyServer deriving (Typeable, Eq, Show, Bounded, Enum)
550data EmptyServer = EmptyServer deriving (Typeable, Eq, Show, Bounded, Enum)
538
551
servant-server/test/Servant/ServerSpec.hs+5
@@ -10,6 +10,11 @@
10{-# LANGUAGE TypeFamilies #-}
10{-# LANGUAGE TypeFamilies #-}
11{-# LANGUAGE TypeOperators #-}
11{-# LANGUAGE TypeOperators #-}
12{-# LANGUAGE TypeSynonymInstances #-}
12{-# LANGUAGE TypeSynonymInstances #-}
13+#if __GLASGOW_HASKELL__ >= 800
14+{-# OPTIONS_GHC -freduction-depth=100 #-}
15+#else
16+{-# OPTIONS_GHC -fcontext-stack=100 #-}
17+#endif
13
18
14module Servant.ServerSpec where
19module Servant.ServerSpec where
15
20
servant/servant.cabal+1
@@ -38,6 +38,7 @@ library
38 Servant.API.BasicAuth
38 Servant.API.BasicAuth
39 Servant.API.Capture
39 Servant.API.Capture
40 Servant.API.ContentTypes
40 Servant.API.ContentTypes
41+ Servant.API.Description
41 Servant.API.Empty
42 Servant.API.Empty
42 Servant.API.Experimental.Auth
43 Servant.API.Experimental.Auth
43 Servant.API.Header
44 Servant.API.Header
servant/src/Servant/API.hs+4
@@ -34,6 +34,9 @@ module Servant.API (
34 -- * Authentication
34 -- * Authentication
35 module Servant.API.BasicAuth,
35 module Servant.API.BasicAuth,
36
36
37+ -- * Endpoints description
38+ module Servant.API.Description,
39+
37 -- * Content Types
40 -- * Content Types
38 module Servant.API.ContentTypes,
41 module Servant.API.ContentTypes,
39 -- | Serializing and deserializing types based on @Accept@ and
42 -- | Serializing and deserializing types based on @Accept@ and
@@ -68,6 +71,7 @@ import Servant.API.ContentTypes (Accept (..), FormUrlEncoded,
68 MimeRender (..), NoContent (NoContent),
71 MimeRender (..), NoContent (NoContent),
69 MimeUnrender (..), OctetStream,
72 MimeUnrender (..), OctetStream,
70 PlainText)
73 PlainText)
74+import Servant.API.Description (Description, Summary)
71import Servant.API.Empty (EmptyAPI (..))
75import Servant.API.Empty (EmptyAPI (..))
72import Servant.API.Experimental.Auth (AuthProtect)
76import Servant.API.Experimental.Auth (AuthProtect)
73import Servant.API.Header (Header (..))
77import Servant.API.Header (Header (..))
servant/src/Servant/API/Description.hsnew file+39
@@ -0,0 +1,39 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE DeriveDataTypeable #-}
3+{-# LANGUAGE PolyKinds #-}
4+{-# OPTIONS_HADDOCK not-home #-}
5+module Servant.API.Description (Description, Summary) where
6+
7+import Data.Typeable (Typeable)
8+import GHC.TypeLits (Symbol)
9+-- | Add a short summary for (part of) API.
10+--
11+-- Example:
12+--
13+-- >>> type MyApi = Summary "Get book by ISBN." :> "books" :> Capture "isbn" Text :> Get '[JSON] Book
14+data Summary (sym :: Symbol)
15+ deriving (Typeable)
16+
17+-- | Add more verbose description for (part of) API.
18+--
19+-- Example:
20+--
21+-- >>> :{
22+--type MyApi = Description
23+-- "This comment is visible in multiple Servant interpretations \
24+-- \and can be really long if necessary. \
25+-- \Haskell multiline support is not perfect \
26+-- \but it's still very readable."
27+-- :> Get '[JSON] Book
28+-- :}
29+data Description (sym :: Symbol)
30+ deriving (Typeable)
31+
32+-- $setup
33+-- >>> import Servant.API
34+-- >>> import Data.Aeson
35+-- >>> import Data.Text
36+-- >>> data Book
37+-- >>> instance ToJSON Book where { toJSON = undefined }
38+-- >>> data SourceFile
39+-- >>> instance ToJSON SourceFile where { toJSON = undefined }
servant/src/Servant/API/Internal/Test/ComprehensiveAPI.hs+2
@@ -38,6 +38,8 @@ type ComprehensiveAPIWithoutRaw =
38 Verb 'POST 204 '[JSON] Int :<|>
38 Verb 'POST 204 '[JSON] Int :<|>
39 WithNamedContext "foo" '[] GET :<|>
39 WithNamedContext "foo" '[] GET :<|>
40 CaptureAll "foo" Int :> GET :<|>
40 CaptureAll "foo" Int :> GET :<|>
41+ Summary "foo" :> GET :<|>
42+ Description "foo" :> GET :<|>
41 EmptyAPI
43 EmptyAPI
42
44
43comprehensiveAPIWithoutRaw :: Proxy ComprehensiveAPIWithoutRaw
45comprehensiveAPIWithoutRaw :: Proxy ComprehensiveAPIWithoutRaw