diff --git a/changelog.d/operation-id-combinator b/changelog.d/operation-id-combinator new file mode 100644 index 000000000..b179d6a5f --- /dev/null +++ b/changelog.d/operation-id-combinator @@ -0,0 +1,9 @@ +synopsis: Add OperationId combinator. +prs: #1277 +issues: #1276 + +description: { + +Adds a combinator that allows overriding the `operationId` field of a Swagger entry. + +} diff --git a/servant-client-core/src/Servant/Client/Core/HasClient.hs b/servant-client-core/src/Servant/Client/Core/HasClient.hs index 783072443..a67b74298 100644 --- a/servant-client-core/src/Servant/Client/Core/HasClient.hs +++ b/servant-client-core/src/Servant/Client/Core/HasClient.hs @@ -47,12 +47,12 @@ import Servant.API EmptyAPI, FramingRender (..), FramingUnrender (..), FromSourceIO (..), Header', Headers (..), HttpVersion, IsSecure, MimeRender (mimeRender), - MimeUnrender (mimeUnrender), NoContent (NoContent), QueryFlag, - QueryParam', QueryParams, Raw, ReflectMethod (..), RemoteHost, - ReqBody', SBoolI, Stream, StreamBody', Summary, ToHttpApiData, - ToSourceIO (..), Vault, Verb, NoContentVerb, WithNamedContext, - contentType, getHeadersHList, getResponse, toQueryParam, - toUrlPiece) + MimeUnrender (mimeUnrender), NoContent (NoContent), OperationId, + QueryFlag, QueryParam', QueryParams, Raw, ReflectMethod (..), + RemoteHost, ReqBody', SBoolI, Stream, StreamBody', Summary, + ToHttpApiData, ToSourceIO (..), Vault, Verb, NoContentVerb, + WithNamedContext, contentType, getHeadersHList, getResponse, + toQueryParam, toUrlPiece) import Servant.API.ContentTypes (contentTypes) import Servant.API.Modifiers @@ -404,6 +404,14 @@ instance HasClient m api => HasClient m (Description desc :> api) where hoistClientMonad pm _ f cl = hoistClientMonad pm (Proxy :: Proxy api) f cl +-- | Ignore @'Description'@ in client functions. +instance (KnownSymbol opid, HasClient m api) => HasClient m (OperationId opid :> api) where + type Client m (OperationId opid :> api) = Client m api + + clientWithRoute pm Proxy = clientWithRoute pm (Proxy :: Proxy api) + + hoistClientMonad pm _ f cl = hoistClientMonad pm (Proxy :: Proxy api) f cl + -- | If you use a 'QueryParam' in one of your endpoints in your API, -- the corresponding querying function will automatically take -- an additional argument of the type specified by your 'QueryParam', diff --git a/servant-server/src/Servant/Server/Internal.hs b/servant-server/src/Servant/Server/Internal.hs index f1a24a194..1a7c3af8e 100644 --- a/servant-server/src/Servant/Server/Internal.hs +++ b/servant-server/src/Servant/Server/Internal.hs @@ -72,11 +72,11 @@ import Servant.API ((:<|>) (..), (:>), Accept (..), BasicAuth, Capture', CaptureAll, Description, EmptyAPI, FramingRender (..), FramingUnrender (..), FromSourceIO (..), Header', If, - IsSecure (..), QueryFlag, QueryParam', QueryParams, Raw, - ReflectMethod (reflectMethod), RemoteHost, ReqBody', - SBool (..), SBoolI (..), SourceIO, Stream, StreamBody', - Summary, ToSourceIO (..), Vault, Verb, NoContentVerb, - WithNamedContext) + IsSecure (..), OperationId, QueryFlag, QueryParam', + QueryParams, Raw, ReflectMethod (reflectMethod), RemoteHost, + ReqBody', SBool (..), SBoolI (..), SourceIO, Stream, + StreamBody', Summary, ToSourceIO (..), Vault, Verb, + NoContentVerb, WithNamedContext) import Servant.API.ContentTypes (AcceptHeader (..), AllCTRender (..), AllCTUnrender (..), AllMime, MimeRender (..), MimeUnrender (..), canHandleAcceptH, @@ -718,6 +718,13 @@ instance HasServer api ctx => HasServer (Description desc :> api) ctx where route _ = route (Proxy :: Proxy api) hoistServerWithContext _ pc nt s = hoistServerWithContext (Proxy :: Proxy api) pc nt s +-- | Ignore @'OperationId'@ in server handlers. +instance HasServer api ctx => HasServer (OperationId opid :> api) ctx where + type ServerT (OperationId opid :> api) m = ServerT api m + + route _ = route (Proxy :: Proxy api) + hoistServerWithContext _ pc nt s = hoistServerWithContext (Proxy :: Proxy api) pc nt s + -- | Singleton type representing a server that serves an empty API. data EmptyServer = EmptyServer deriving (Typeable, Eq, Show, Bounded, Enum) diff --git a/servant/src/Servant/API.hs b/servant/src/Servant/API.hs index 772a38878..38b307e9c 100644 --- a/servant/src/Servant/API.hs +++ b/servant/src/Servant/API.hs @@ -87,7 +87,7 @@ import Servant.API.ContentTypes MimeUnrender (..), NoContent (NoContent), OctetStream, PlainText) import Servant.API.Description - (Description, Summary) + (Description, OperationId, Summary) import Servant.API.Empty (EmptyAPI (..)) import Servant.API.Experimental.Auth diff --git a/servant/src/Servant/API/Description.hs b/servant/src/Servant/API/Description.hs index 18c54322f..75439c0f5 100644 --- a/servant/src/Servant/API/Description.hs +++ b/servant/src/Servant/API/Description.hs @@ -10,6 +10,7 @@ module Servant.API.Description ( -- * Combinators Description, Summary, + OperationId, -- * Used as modifiers FoldDescription, FoldDescription', @@ -46,6 +47,17 @@ data Summary (sym :: Symbol) data Description (sym :: Symbol) deriving (Typeable) +-- | Specify the operation ID used by swagger. +-- +-- Example: +-- +-- >>> :{ +--type MyApi = OperationId "getBooks" +-- :> Get '[JSON] Book +-- :} +data OperationId (sym :: Symbol) + deriving (Typeable) + -- | Fold list of modifiers to extract description as a type-level String. -- -- >>> :kind! FoldDescription '[]