git.iko.soy/typeable/servant
on master help sign in
Merge pull request #767 from fierce-katie/docs-combinators

Description and Summary combinators

commit50be3a263b403aaccd244d83a971b56efc40553c authorOleg Grenrus <oleg.grenrus@iki.fi> dateWed 16 Aug 2017, 15:31 (9 years ago) parent7fb6b70be0878c
10 files changed+119−1
servant-client/src/Servant/Client.hs+12 servant-docs/src/Servant/Docs/Internal.hs+21 servant-docs/test/Servant/DocsSpec.hs+7 servant-foreign/src/Servant/Foreign/Internal.hs+14 servant-server/src/Servant/Server/Internal.hs+14−1 servant-server/test/Servant/ServerSpec.hs+5 servant/servant.cabal+1 servant/src/Servant/API.hs+4 servant/src/Servant/API/Description.hs+39 servant/src/Servant/API/Internal/Test/ComprehensiveAPI.hs+2
servant-client/src/Servant/Client.hs+12
@@ -263,6 +263,18 @@ instance HasClient api
263263 clientWithRoute Proxy =
264264 clientWithRoute (Proxy :: Proxy api)
265265
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+
266278-- | If you use a 'QueryParam' in one of your endpoints in your API,
267279-- the corresponding querying function will automatically take
268280-- 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
807807 docsFor _proxy (endpoint, action) _ =
808808 single endpoint action
809809
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+
810831-- TODO: We use 'AllMimeRender' here because we need to be able to show the
811832-- example data. However, there's no reason to believe that the instances of
812833-- 'AllMimeUnrender' and 'AllMimeRender' actually agree (or to suppose that
servant-docs/test/Servant/DocsSpec.hs+7
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12{-# LANGUAGE DataKinds #-}
23{-# LANGUAGE DeriveGeneric #-}
34{-# LANGUAGE FlexibleContexts #-}
@@ -7,6 +8,12 @@
78{-# LANGUAGE TypeOperators #-}
89{-# LANGUAGE TypeSynonymInstances #-}
910{-# 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+
1017module Servant.DocsSpec where
1118
1219import Control.Lens
servant-foreign/src/Servant/Foreign/Internal.hs+14
@@ -350,6 +350,20 @@ instance HasForeign lang ftype api
350350 foreignFor lang ftype Proxy req =
351351 foreignFor lang ftype (Proxy :: Proxy api) req
352352
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+
353367-- | Utility class used by 'listFromAPI' which computes
354368-- the data needed to generate a function for each endpoint
355369-- 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
5858 IsSecure(..), Header, QueryFlag,
5959 QueryParam, QueryParams, Raw,
6060 RemoteHost, ReqBody, Vault,
61− WithNamedContext)
61+ WithNamedContext,
62+ Description, Summary)
6263import Servant.API.ContentTypes (AcceptHeader (..),
6364 AllCTRender (..),
6465 AllCTUnrender (..),
@@ -533,6 +534,18 @@ instance HasServer api context => HasServer (HttpVersion :> api) context where
533534 route Proxy context subserver =
534535 route (Proxy :: Proxy api) context (passToServer subserver httpVersion)
535536
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+
536549-- | Singleton type representing a server that serves an empty API.
537550data EmptyServer = EmptyServer deriving (Typeable, Eq, Show, Bounded, Enum)
538551
servant-server/test/Servant/ServerSpec.hs+5
@@ -10,6 +10,11 @@
1010{-# LANGUAGE TypeFamilies #-}
1111{-# LANGUAGE TypeOperators #-}
1212{-# LANGUAGE TypeSynonymInstances #-}
13+#if __GLASGOW_HASKELL__ >= 800
14+{-# OPTIONS_GHC -freduction-depth=100 #-}
15+#else
16+{-# OPTIONS_GHC -fcontext-stack=100 #-}
17+#endif
1318
1419module Servant.ServerSpec where
1520
servant/servant.cabal+1
@@ -38,6 +38,7 @@ library
3838 Servant.API.BasicAuth
3939 Servant.API.Capture
4040 Servant.API.ContentTypes
41+ Servant.API.Description
4142 Servant.API.Empty
4243 Servant.API.Experimental.Auth
4344 Servant.API.Header
servant/src/Servant/API.hs+4
@@ -34,6 +34,9 @@ module Servant.API (
3434 -- * Authentication
3535 module Servant.API.BasicAuth,
3636
37+ -- * Endpoints description
38+ module Servant.API.Description,
39+
3740 -- * Content Types
3841 module Servant.API.ContentTypes,
3942 -- | Serializing and deserializing types based on @Accept@ and
@@ -68,6 +71,7 @@ import Servant.API.ContentTypes (Accept (..), FormUrlEncoded,
6871 MimeRender (..), NoContent (NoContent),
6972 MimeUnrender (..), OctetStream,
7073 PlainText)
74+import Servant.API.Description (Description, Summary)
7175import Servant.API.Empty (EmptyAPI (..))
7276import Servant.API.Experimental.Auth (AuthProtect)
7377import 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 =
3838 Verb 'POST 204 '[JSON] Int :<|>
3939 WithNamedContext "foo" '[] GET :<|>
4040 CaptureAll "foo" Int :> GET :<|>
41+ Summary "foo" :> GET :<|>
42+ Description "foo" :> GET :<|>
4143 EmptyAPI
4244
4345comprehensiveAPIWithoutRaw :: Proxy ComprehensiveAPIWithoutRaw