diff --git a/changelog.d/1-api-changes/introduce-v5 b/changelog.d/1-api-changes/introduce-v5 new file mode 100644 index 0000000000..0d2498b3d3 --- /dev/null +++ b/changelog.d/1-api-changes/introduce-v5 @@ -0,0 +1 @@ +Introduce v5 development version diff --git a/docs/src/developer/developer/api-versioning.md b/docs/src/developer/developer/api-versioning.md index 053c830749..3cf3613454 100644 --- a/docs/src/developer/developer/api-versioning.md +++ b/docs/src/developer/developer/api-versioning.md @@ -110,8 +110,7 @@ are several steps to make apart from deciding what endpoint changes are part of the version: - In `wire-api` extend the `Version` type with a new version by appending the - new version to the end, e.g., by adding `V4`. Make sure to update its - `ToSchema` instance, + new version to the end, e.g., by adding `V4`. - In the same `Version` module update the `developmentVersions` value to list only the new version, - Consider updating the `backendApiVersion` value in Stern, which is diff --git a/integration/test/Test/Brig.hs b/integration/test/Test/Brig.hs index 98e046fa6d..3380d8400c 100644 --- a/integration/test/Test/Brig.hs +++ b/integration/test/Test/Brig.hs @@ -139,7 +139,7 @@ testCrudOAuthClient = do testSwagger :: HasCallStack => App () testSwagger = do let existingVersions :: [Int] - existingVersions = [0, 1, 2, 3, 4] + existingVersions = [0, 1, 2, 3, 4, 5] internalApis :: [String] internalApis = ["brig", "cannon", "cargohold", "cannon", "spar"] diff --git a/libs/wire-api/src/Wire/API/Error.hs b/libs/wire-api/src/Wire/API/Error.hs index 1edf2eda32..304f11596e 100644 --- a/libs/wire-api/src/Wire/API/Error.hs +++ b/libs/wire-api/src/Wire/API/Error.hs @@ -68,6 +68,7 @@ import Servant import Servant.Swagger import Wire.API.Routes.MultiVerb import Wire.API.Routes.Named (Named) +import Wire.API.Routes.Version -- | Runtime representation of a statically-known error. data DynError = DynError @@ -167,6 +168,10 @@ instance RoutesToPaths api => RoutesToPaths (CanThrow err :> api) where instance RoutesToPaths api => RoutesToPaths (CanThrowMany errs :> api) where getRoutes = getRoutes @api +type instance + SpecialiseToVersion v (CanThrow e :> api) = + CanThrow e :> SpecialiseToVersion v api + instance (HasServer api ctx) => HasServer (CanThrow e :> api) ctx where type ServerT (CanThrow e :> api) m = ServerT api m @@ -185,6 +190,10 @@ instance where toSwagger _ = addToSwagger @e (toSwagger (Proxy @api)) +type instance + SpecialiseToVersion v (CanThrowMany es :> api) = + CanThrowMany es :> SpecialiseToVersion v api + instance HasSwagger api => HasSwagger (CanThrowMany '() :> api) where toSwagger _ = toSwagger (Proxy @api) diff --git a/libs/wire-api/src/Wire/API/MakesFederatedCall.hs b/libs/wire-api/src/Wire/API/MakesFederatedCall.hs index f1f571106a..fbc133d672 100644 --- a/libs/wire-api/src/Wire/API/MakesFederatedCall.hs +++ b/libs/wire-api/src/Wire/API/MakesFederatedCall.hs @@ -48,6 +48,7 @@ import Servant.Swagger import Test.QuickCheck (Arbitrary) import TransitiveAnns.Types import Unsafe.Coerce (unsafeCoerce) +import Wire.API.Routes.Version import Wire.Arbitrary (GenericUniform (..)) -- | This function exists only to provide a convenient place for the @@ -151,6 +152,10 @@ type family ShowComponent (x :: Component) = (res :: Symbol) | res -> x where ShowComponent 'Galley = "galley" ShowComponent 'Cargohold = "cargohold" +type instance + SpecialiseToVersion v (MakesFederatedCall comp name :> api) = + MakesFederatedCall comp name :> SpecialiseToVersion v api + -- | 'MakesFederatedCall' annotates the swagger documentation with an extension -- tag @x-wire-makes-federated-calls-to@. instance (HasSwagger api, KnownSymbol name, KnownSymbol (ShowComponent comp)) => HasSwagger (MakesFederatedCall comp name :> api :: Type) where diff --git a/libs/wire-api/src/Wire/API/Routes/API.hs b/libs/wire-api/src/Wire/API/Routes/API.hs index 607933e2ed..b43569bf76 100644 --- a/libs/wire-api/src/Wire/API/Routes/API.hs +++ b/libs/wire-api/src/Wire/API/Routes/API.hs @@ -16,7 +16,8 @@ -- with this program. If not, see . module Wire.API.Routes.API - ( API, + ( ServiceAPI (..), + API, hoistAPIHandler, hoistAPI, mkAPI, @@ -29,14 +30,28 @@ module Wire.API.Routes.API where import Data.Domain +import Data.Kind import Data.Proxy +import Data.Swagger qualified as S import Imports import Polysemy import Polysemy.Error import Polysemy.Internal import Servant hiding (Union) +import Servant.Swagger import Wire.API.Error import Wire.API.Routes.Named +import Wire.API.Routes.Version + +class ServiceAPI service (v :: Version) where + type ServiceAPIRoutes service + type SpecialisedAPIRoutes v service :: Type + type SpecialisedAPIRoutes v service = SpecialiseToVersion v (ServiceAPIRoutes service) + serviceSwagger :: HasSwagger (SpecialisedAPIRoutes v service) => S.Swagger + serviceSwagger = toSwagger (Proxy @(SpecialisedAPIRoutes v service)) + +instance ServiceAPI VersionAPITag v where + type ServiceAPIRoutes VersionAPITag = VersionAPI -- | A Servant handler on a polysemy stack. This is used to help with type inference. newtype API api r = API {unAPI :: ServerT api (Sem r)} diff --git a/libs/wire-api/src/Wire/API/Routes/Bearer.hs b/libs/wire-api/src/Wire/API/Routes/Bearer.hs index b2b0c1918e..545db5254d 100644 --- a/libs/wire-api/src/Wire/API/Routes/Bearer.hs +++ b/libs/wire-api/src/Wire/API/Routes/Bearer.hs @@ -26,6 +26,7 @@ import Data.Text.Encoding qualified as T import Imports import Servant import Servant.Swagger +import Wire.API.Routes.Version newtype Bearer a = Bearer {unBearer :: a} @@ -42,6 +43,10 @@ type BearerQueryParam = [Lenient, Description "Access token"] "access_token" +type instance + SpecialiseToVersion v (Bearer a :> api) = + Bearer a :> SpecialiseToVersion v api + instance HasSwagger api => HasSwagger (Bearer a :> api) where toSwagger _ = toSwagger (Proxy @api) diff --git a/libs/wire-api/src/Wire/API/Routes/Cookies.hs b/libs/wire-api/src/Wire/API/Routes/Cookies.hs index 644435d205..10383904cc 100644 --- a/libs/wire-api/src/Wire/API/Routes/Cookies.hs +++ b/libs/wire-api/src/Wire/API/Routes/Cookies.hs @@ -29,6 +29,7 @@ import Imports import Servant import Servant.Swagger import Web.Cookie (parseCookies) +import Wire.API.Routes.Version data (:::) a b @@ -58,6 +59,10 @@ newtype CookieTuple cs = CookieTuple {unCookieTuple :: NP I (CookieTypes cs)} type CookieMap = Map ByteString (NonEmpty ByteString) +type instance + SpecialiseToVersion v (Cookies cs :> api) = + Cookies cs :> SpecialiseToVersion v api + instance HasSwagger api => HasSwagger (Cookies cs :> api) where toSwagger _ = toSwagger (Proxy @api) diff --git a/libs/wire-api/src/Wire/API/Routes/LowLevelStream.hs b/libs/wire-api/src/Wire/API/Routes/LowLevelStream.hs index 209afbf64a..d9287bd5fa 100644 --- a/libs/wire-api/src/Wire/API/Routes/LowLevelStream.hs +++ b/libs/wire-api/src/Wire/API/Routes/LowLevelStream.hs @@ -37,6 +37,7 @@ import Servant.Server hiding (respond) import Servant.Server.Internal import Servant.Swagger as S import Servant.Swagger.Internal as S +import Wire.API.Routes.Version -- FUTUREWORK: make it possible to generate headers at runtime data LowLevelStream method status (headers :: [(Symbol, Symbol)]) desc ctype @@ -84,6 +85,10 @@ instance status = statusFromNat (Proxy :: Proxy status) extraHeaders = renderHeaders @headers +type instance + SpecialiseToVersion v (LowLevelStream m s h d t) = + LowLevelStream m s h d t + instance (Accept ctype, KnownNat status, KnownSymbol desc, SwaggerMethod method) => HasSwagger (LowLevelStream method status headers desc ctype) diff --git a/libs/wire-api/src/Wire/API/Routes/Public.hs b/libs/wire-api/src/Wire/API/Routes/Public.hs index befd085500..8ad302b6dd 100644 --- a/libs/wire-api/src/Wire/API/Routes/Public.hs +++ b/libs/wire-api/src/Wire/API/Routes/Public.hs @@ -55,6 +55,7 @@ import Servant.Server.Internal.DelayedIO import Servant.Server.Internal.Router (Router) import Servant.Swagger (HasSwagger (toSwagger)) import Wire.API.OAuth qualified as OAuth +import Wire.API.Routes.Version mapRequestArgument :: forall mods a b. @@ -196,20 +197,29 @@ type ZOptHostHeader = instance HasSwagger api => HasSwagger (ZHostOpt :> api) where toSwagger _ = toSwagger (Proxy @api) +type instance SpecialiseToVersion v (ZHostOpt :> api) = ZHostOpt :> SpecialiseToVersion v api + +addZAuthSwagger :: Swagger -> Swagger +addZAuthSwagger s = + s + & securityDefinitions <>~ SecurityDefinitions (InsOrdHashMap.singleton "ZAuth" secScheme) + & security <>~ [SecurityRequirement $ InsOrdHashMap.singleton "ZAuth" []] + where + secScheme = + SecurityScheme + { _securitySchemeType = SecuritySchemeApiKey (ApiKeyParams "Authorization" ApiKeyHeader), + _securitySchemeDescription = Just "Must be a token retrieved by calling 'POST /login' or 'POST /access'. It must be presented in this format: 'Bearer \\'." + } + +type instance + SpecialiseToVersion v (ZAuthServant t opts :> api) = + ZAuthServant t opts :> SpecialiseToVersion v api + instance HasSwagger api => HasSwagger (ZAuthServant 'ZAuthUser _opts :> api) where - toSwagger _ = - toSwagger (Proxy @api) - & securityDefinitions <>~ SecurityDefinitions (InsOrdHashMap.singleton "ZAuth" secScheme) - & security <>~ [SecurityRequirement $ InsOrdHashMap.singleton "ZAuth" []] - where - secScheme = - SecurityScheme - { _securitySchemeType = SecuritySchemeApiKey (ApiKeyParams "Authorization" ApiKeyHeader), - _securitySchemeDescription = Just "Must be a token retrieved by calling 'POST /login' or 'POST /access'. It must be presented in this format: 'Bearer \\'." - } + toSwagger _ = addZAuthSwagger (toSwagger (Proxy @api)) instance HasSwagger api => HasSwagger (ZAuthServant 'ZLocalAuthUser opts :> api) where - toSwagger _ = toSwagger (Proxy @(ZAuthServant 'ZAuthUser opts :> api)) + toSwagger _ = addZAuthSwagger (toSwagger (Proxy @api)) instance HasLink endpoint => HasLink (ZAuthServant usr opts :> endpoint) where type MkLink (ZAuthServant _ _ :> endpoint) a = MkLink endpoint a @@ -286,11 +296,18 @@ instance ToSchema a => ToSchema (Headers ls a) where data DescriptionOAuthScope (scope :: OAuth.OAuthScope) -instance (HasSwagger api, OAuth.IsOAuthScope scope) => HasSwagger (DescriptionOAuthScope scope :> api) where - toSwagger _ = toSwagger (Proxy @api) & addScopeDescription - where - addScopeDescription :: Swagger -> Swagger - addScopeDescription = allOperations . description %~ Just . (<> "\nOAuth scope: `" <> cs (toByteString (OAuth.toOAuthScope @scope)) <> "`") . fold +type instance + SpecialiseToVersion v (DescriptionOAuthScope scope :> api) = + DescriptionOAuthScope scope :> SpecialiseToVersion v api + +instance + (HasSwagger api, OAuth.IsOAuthScope scope) => + HasSwagger (DescriptionOAuthScope scope :> api) + where + toSwagger _ = addScopeDescription @scope (toSwagger (Proxy @api)) + +addScopeDescription :: forall scope. OAuth.IsOAuthScope scope => Swagger -> Swagger +addScopeDescription = allOperations . description %~ Just . (<> "\nOAuth scope: `" <> cs (toByteString (OAuth.toOAuthScope @scope)) <> "`") . fold instance (HasServer api ctx) => HasServer (DescriptionOAuthScope scope :> api) ctx where type ServerT (DescriptionOAuthScope scope :> api) m = ServerT api m diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Brig.hs b/libs/wire-api/src/Wire/API/Routes/Public/Brig.hs index ceec7e951c..b99aa0e729 100644 --- a/libs/wire-api/src/Wire/API/Routes/Public/Brig.hs +++ b/libs/wire-api/src/Wire/API/Routes/Public/Brig.hs @@ -39,7 +39,6 @@ import Imports hiding (head) import Network.Wai.Utilities import Servant (JSON) import Servant hiding (Handler, JSON, addHeader, respond) -import Servant.Swagger (HasSwagger (toSwagger)) import Servant.Swagger.Internal.Orphans () import Wire.API.Call.Config (RTCConfiguration) import Wire.API.Connection hiding (MissingLegalholdConsent) @@ -51,6 +50,7 @@ import Wire.API.MLS.Servant import Wire.API.MakesFederatedCall import Wire.API.OAuth import Wire.API.Properties +import Wire.API.Routes.API import Wire.API.Routes.Bearer import Wire.API.Routes.Cookies import Wire.API.Routes.MultiVerb @@ -93,8 +93,10 @@ type BrigAPI = :<|> SystemSettingsAPI :<|> OAuthAPI -brigSwagger :: Swagger -brigSwagger = toSwagger (Proxy @BrigAPI) +data BrigAPITag + +instance ServiceAPI BrigAPITag v where + type ServiceAPIRoutes BrigAPITag = BrigAPI ------------------------------------------------------------------------------- -- User API diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Brig/OAuth.hs b/libs/wire-api/src/Wire/API/Routes/Public/Brig/OAuth.hs index 2a37bd71c6..0a4adf5240 100644 --- a/libs/wire-api/src/Wire/API/Routes/Public/Brig/OAuth.hs +++ b/libs/wire-api/src/Wire/API/Routes/Public/Brig/OAuth.hs @@ -19,14 +19,13 @@ module Wire.API.Routes.Public.Brig.OAuth where import Data.Id as Id import Data.SOP -import Data.Swagger (Swagger) import Imports hiding (exp, head) import Servant (JSON) import Servant hiding (Handler, JSON, Tagged, addHeader, respond) -import Servant.Swagger import Servant.Swagger.Internal.Orphans () import Wire.API.Error import Wire.API.OAuth +import Wire.API.Routes.API import Wire.API.Routes.MultiVerb import Wire.API.Routes.Named (Named (..)) import Wire.API.Routes.Public @@ -156,5 +155,7 @@ instance AsUnion CreateOAuthAuthorizationCodeResponses CreateOAuthCodeResponse w fromUnion (S (S (S (S (Z (I _)))))) = CreateOAuthCodeRedirectUrlMissMatch fromUnion (S (S (S (S (S x))))) = case x of {} -swaggerDoc :: Swagger -swaggerDoc = toSwagger (Proxy @OAuthAPI) +data OAuthAPITag + +instance ServiceAPI OAuthAPITag v where + type ServiceAPIRoutes OAuthAPITag = OAuthAPI diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Cannon.hs b/libs/wire-api/src/Wire/API/Routes/Public/Cannon.hs index ceacf45518..eda1f01a8e 100644 --- a/libs/wire-api/src/Wire/API/Routes/Public/Cannon.hs +++ b/libs/wire-api/src/Wire/API/Routes/Public/Cannon.hs @@ -18,14 +18,13 @@ module Wire.API.Routes.Public.Cannon where import Data.Id -import Data.Swagger import Servant -import Servant.Swagger +import Wire.API.Routes.API import Wire.API.Routes.Named import Wire.API.Routes.Public (ZConn, ZUser) import Wire.API.Routes.WebSocket -type PublicAPI = +type CannonAPI = Named "await-notifications" ( Summary "Establish websocket connection" @@ -43,5 +42,7 @@ type PublicAPI = :> WebSocketPending ) -swaggerDoc :: Swagger -swaggerDoc = toSwagger (Proxy @PublicAPI) +data CannonAPITag + +instance ServiceAPI CannonAPITag v where + type ServiceAPIRoutes CannonAPITag = CannonAPI diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Cargohold.hs b/libs/wire-api/src/Wire/API/Routes/Public/Cargohold.hs index 2260d3953e..1ce9dd600c 100644 --- a/libs/wire-api/src/Wire/API/Routes/Public/Cargohold.hs +++ b/libs/wire-api/src/Wire/API/Routes/Public/Cargohold.hs @@ -22,16 +22,15 @@ import Data.Kind import Data.Metrics.Servant import Data.Qualified import Data.SOP -import Data.Swagger qualified as Swagger import Imports import Servant -import Servant.Swagger.Internal import Servant.Swagger.Internal.Orphans () import URI.ByteString import Wire.API.Asset import Wire.API.Error import Wire.API.Error.Cargohold import Wire.API.MakesFederatedCall +import Wire.API.Routes.API import Wire.API.Routes.AssetBody import Wire.API.Routes.MultiVerb import Wire.API.Routes.Public @@ -56,8 +55,9 @@ type instance ApplyPrincipalPath 'BotPrincipalTag api = ZBot :> "bot" :> "assets type instance ApplyPrincipalPath 'ProviderPrincipalTag api = ZProvider :> "provider" :> "assets" :> api -instance HasSwagger (ApplyPrincipalPath tag api) => HasSwagger (tag :> api) where - toSwagger _ = toSwagger (Proxy @(ApplyPrincipalPath tag api)) +type instance + SpecialiseToVersion v ((tag :: PrincipalTag) :> api) = + SpecialiseToVersion v (ApplyPrincipalPath tag api) instance HasServer (ApplyPrincipalPath tag api) ctx => HasServer (tag :> api) ctx where type ServerT (tag :> api) m = ServerT (ApplyPrincipalPath tag api) m @@ -90,7 +90,7 @@ type GetAsset = '[ErrorResponse 'AssetNotFound, AssetRedirect] (Maybe (AssetLocation Absolute)) -type ServantAPI = +type CargoholdAPI = ( Summary "Renew an asset token" :> Until 'V2 :> CanThrow 'AssetNotFound @@ -315,5 +315,7 @@ type MainAPI = () ) -swaggerDoc :: Swagger.Swagger -swaggerDoc = toSwagger (Proxy @ServantAPI) +data CargoholdAPITag + +instance ServiceAPI CargoholdAPITag v where + type ServiceAPIRoutes CargoholdAPITag = CargoholdAPI diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Galley.hs b/libs/wire-api/src/Wire/API/Routes/Public/Galley.hs index ff1b80fe0b..d24c473738 100644 --- a/libs/wire-api/src/Wire/API/Routes/Public/Galley.hs +++ b/libs/wire-api/src/Wire/API/Routes/Public/Galley.hs @@ -20,11 +20,9 @@ module Wire.API.Routes.Public.Galley where -import Data.SOP -import Data.Swagger qualified as Swagger import Servant hiding (WithStatus) -import Servant.Swagger.Internal import Servant.Swagger.Internal.Orphans () +import Wire.API.Routes.API import Wire.API.Routes.Public.Galley.Bot import Wire.API.Routes.Public.Galley.Conversation import Wire.API.Routes.Public.Galley.CustomBackend @@ -37,7 +35,7 @@ import Wire.API.Routes.Public.Galley.TeamConversation import Wire.API.Routes.Public.Galley.TeamMember import Wire.API.Routes.Public.Galley.TeamNotification (TeamNotificationAPI) -type ServantAPI = +type GalleyAPI = ConversationAPI :<|> TeamConversationAPI :<|> MessagingAPI @@ -50,5 +48,7 @@ type ServantAPI = :<|> TeamMemberAPI :<|> TeamNotificationAPI -swaggerDoc :: Swagger.Swagger -swaggerDoc = toSwagger (Proxy @ServantAPI) +data GalleyAPITag + +instance ServiceAPI GalleyAPITag v where + type ServiceAPIRoutes GalleyAPITag = GalleyAPI diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Gundeck.hs b/libs/wire-api/src/Wire/API/Routes/Public/Gundeck.hs index 7fad8afba9..b2d0d329da 100644 --- a/libs/wire-api/src/Wire/API/Routes/Public/Gundeck.hs +++ b/libs/wire-api/src/Wire/API/Routes/Public/Gundeck.hs @@ -19,15 +19,13 @@ module Wire.API.Routes.Public.Gundeck where import Data.Id (ClientId) import Data.Range -import Data.SOP -import Data.Swagger qualified as Swagger import Imports import Servant -import Servant.Swagger import Wire.API.Error import Wire.API.Error.Gundeck as E import Wire.API.Notification import Wire.API.Push.V2.Token +import Wire.API.Routes.API import Wire.API.Routes.MultiVerb import Wire.API.Routes.Named import Wire.API.Routes.Public @@ -132,5 +130,7 @@ type NotificationAPI = (Maybe QueuedNotificationList) ) -swaggerDoc :: Swagger.Swagger -swaggerDoc = toSwagger (Proxy @GundeckAPI) +data GundeckAPITag + +instance ServiceAPI GundeckAPITag v where + type ServiceAPIRoutes GundeckAPITag = GundeckAPI diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Proxy.hs b/libs/wire-api/src/Wire/API/Routes/Public/Proxy.hs index 4f507e1635..4fa0e100c8 100644 --- a/libs/wire-api/src/Wire/API/Routes/Public/Proxy.hs +++ b/libs/wire-api/src/Wire/API/Routes/Public/Proxy.hs @@ -17,11 +17,9 @@ module Wire.API.Routes.Public.Proxy where -import Data.SOP -import Data.Swagger qualified as Swagger import Servant import Servant.API.Extended.RawM (RawM) -import Servant.Swagger +import Wire.API.Routes.API import Wire.API.Routes.Named type ProxyAPI = @@ -50,6 +48,8 @@ type family ProxyAPISummary name where ProxyAPISummary "gmaps-path" = "[DEPRECATED] proxy: `get /proxy/googlemaps/maps/api/geocode/:path`; see google maps API docs" +data ProxyAPITag + -- | FUTUREWORK(fisx): (1) the verb could be added to the swagger docs in the appropriate -- place here; it's always defined in the `Summary`, but the `RawM` doesn't allow to constrain -- it. (2) there should be a way to make this more type-safe: `assertMethod` in @@ -58,5 +58,5 @@ type family ProxyAPISummary name where -- "api" :> "token" :> OnlyMethod "POST" :> RawM`, and then the `ServerT` instance for -- `OnlyMethod` requires a proxy argument in the handler of the same type. Or something. (am -- i massifly over-engineering things here?) -swaggerDoc :: Swagger.Swagger -swaggerDoc = toSwagger (Proxy @ProxyAPI) +instance ServiceAPI ProxyAPITag v where + type ServiceAPIRoutes ProxyAPITag = ProxyAPI diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Spar.hs b/libs/wire-api/src/Wire/API/Routes/Public/Spar.hs index adaf1c3b72..59b98ddc9e 100644 --- a/libs/wire-api/src/Wire/API/Routes/Public/Spar.hs +++ b/libs/wire-api/src/Wire/API/Routes/Public/Spar.hs @@ -20,19 +20,19 @@ module Wire.API.Routes.Public.Spar where import Data.Id import Data.Proxy import Data.Range -import Data.Swagger (Swagger) import Imports import SAML2.WebSSO qualified as SAML import Servant import Servant.API.Extended import Servant.Multipart -import Servant.Swagger (toSwagger) +import Servant.Swagger import URI.ByteString qualified as URI import Web.Scim.Capabilities.MetaSchema as Scim.Meta import Web.Scim.Class.Auth as Scim.Auth import Web.Scim.Class.User as Scim.User import Wire.API.Error import Wire.API.Error.Brig +import Wire.API.Routes.API import Wire.API.Routes.Internal.Spar import Wire.API.Routes.Public import Wire.API.SwaggerServant @@ -45,7 +45,7 @@ import Wire.API.User.Scim -- FUTUREWORK: use https://hackage.haskell.org/package/servant-0.14.1/docs/Servant-API-Generic.html? -type API = +type SparAPI = "sso" :> APISSO :<|> "identity-providers" :> APIIDP :<|> "scim" :> APIScim @@ -186,5 +186,9 @@ type APIScimTokenDelete = type APIScimTokenList = Get '[JSON] ScimTokenList -swaggerDoc :: Swagger -swaggerDoc = toSwagger (Proxy @API) +data SparAPITag + +instance ServiceAPI SparAPITag v where + type ServiceAPIRoutes SparAPITag = SparAPI + type SpecialisedAPIRoutes v SparAPITag = SparAPI + serviceSwagger = toSwagger (Proxy @SparAPI) diff --git a/libs/wire-api/src/Wire/API/Routes/QualifiedCapture.hs b/libs/wire-api/src/Wire/API/Routes/QualifiedCapture.hs index 4fd030267d..f54cccf4f3 100644 --- a/libs/wire-api/src/Wire/API/Routes/QualifiedCapture.hs +++ b/libs/wire-api/src/Wire/API/Routes/QualifiedCapture.hs @@ -34,6 +34,7 @@ import Servant.API.Modifiers import Servant.Client.Core.HasClient import Servant.Server.Internal.ErrorFormatter import Servant.Swagger +import Wire.API.Routes.Version -- | Capture a value qualified by a domain, with modifiers. data QualifiedCapture' (mods :: [Type]) (capture :: Symbol) (a :: Type) @@ -50,6 +51,10 @@ type WithDomain mods capture a api = :> Capture' mods capture a :> api +type instance + SpecialiseToVersion v (QualifiedCapture' mods capture a :> api) = + QualifiedCapture' mods capture a :> SpecialiseToVersion v api + instance ( Typeable a, ToParamSchema a, diff --git a/libs/wire-api/src/Wire/API/Routes/Version.hs b/libs/wire-api/src/Wire/API/Routes/Version.hs index 95fba40302..826da8873a 100644 --- a/libs/wire-api/src/Wire/API/Routes/Version.hs +++ b/libs/wire-api/src/Wire/API/Routes/Version.hs @@ -22,8 +22,8 @@ module Wire.API.Routes.Version ( -- * API version endpoint VersionAPI, + VersionAPITag, VersionInfo (..), - versionSwagger, versionHeader, VersionHeader, @@ -31,11 +31,15 @@ module Wire.API.Routes.Version Version (..), VersionNumber (..), supportedVersions, + isDevelopmentVersion, developmentVersions, -- * Servant combinators Until, From, + + -- * Swagger instances + SpecialiseToVersion, ) where @@ -49,13 +53,15 @@ import Data.ByteString.Conversion (ToByteString (builder), toByteString') import Data.ByteString.Lazy qualified as LBS import Data.Domain import Data.Schema -import Data.Singletons.TH +import Data.Singletons.Base.TH import Data.Swagger qualified as S -import Data.Text as Text +import Data.Text qualified as Text import Data.Text.Encoding as Text +import GHC.TypeLits import Imports import Servant -import Servant.Swagger +import Servant.API.Extended.RawM +import Wire.API.Routes.MultiVerb import Wire.API.Routes.Named import Wire.API.VersionInfo import Wire.Arbitrary (Arbitrary, GenericUniform (GenericUniform)) @@ -68,7 +74,7 @@ import Wire.Arbitrary (Arbitrary, GenericUniform (GenericUniform)) -- and 'developmentVersions' stay in sync; everything else here should keep working without -- change. See also documentation in the *docs* directory. -- https://docs.wire.com/developer/developer/api-versioning.html#version-bump-checklist -data Version = V0 | V1 | V2 | V3 | V4 +data Version = V0 | V1 | V2 | V3 | V4 | V5 deriving stock (Eq, Ord, Bounded, Enum, Show, Generic) deriving (FromJSON, ToJSON) via (Schema Version) deriving (Arbitrary) via (GenericUniform Version) @@ -85,12 +91,10 @@ versionInt V1 = 1 versionInt V2 = 2 versionInt V3 = 3 versionInt V4 = 4 +versionInt V5 = 5 supportedVersions :: [Version] -supportedVersions = [minBound .. V4] - -developmentVersions :: [Version] -developmentVersions = [V4] +supportedVersions = [minBound .. maxBound] ---------------------------------------------------------------------- @@ -179,7 +183,84 @@ type VersionAPI = :> Get '[JSON] VersionInfo ) -versionSwagger :: S.Swagger -versionSwagger = toSwagger (Proxy @VersionAPI) +data VersionAPITag + +-- Development versions $(genSingletons [''Version]) + +isDevelopmentVersion :: Version -> Bool +isDevelopmentVersion V0 = False +isDevelopmentVersion V1 = False +isDevelopmentVersion V2 = False +isDevelopmentVersion V3 = False +isDevelopmentVersion _ = True + +developmentVersions :: [Version] +developmentVersions = filter isDevelopmentVersion supportedVersions + +-- Version-aware swagger generation + +$(promoteOrdInstances [''Version]) + +type family SpecialiseToVersion (v :: Version) api + +type instance + SpecialiseToVersion v (From w :> api) = + If (v < w) EmptyAPI (SpecialiseToVersion v api) + +type instance + SpecialiseToVersion v (Until w :> api) = + If (v < w) (SpecialiseToVersion v api) EmptyAPI + +type instance + SpecialiseToVersion v ((s :: Symbol) :> api) = + s :> SpecialiseToVersion v api + +type instance + SpecialiseToVersion v (Named n api) = + Named n (SpecialiseToVersion v api) + +type instance + SpecialiseToVersion v (Capture' mod sym a :> api) = + Capture' mod sym a :> SpecialiseToVersion v api + +type instance + SpecialiseToVersion v (Summary s :> api) = + Summary s :> SpecialiseToVersion v api + +type instance + SpecialiseToVersion v (Verb m s t r) = + Verb m s t r + +type instance + SpecialiseToVersion v (MultiVerb m t r x) = + MultiVerb m t r x + +type instance SpecialiseToVersion v RawM = RawM + +type instance + SpecialiseToVersion v (ReqBody t x :> api) = + ReqBody t x :> SpecialiseToVersion v api + +type instance + SpecialiseToVersion v (QueryParam' mods l x :> api) = + QueryParam' mods l x :> SpecialiseToVersion v api + +type instance + SpecialiseToVersion v (Header' opts l x :> api) = + Header' opts l x :> SpecialiseToVersion v api + +type instance + SpecialiseToVersion v (Description desc :> api) = + Description desc :> SpecialiseToVersion v api + +type instance + SpecialiseToVersion v (StreamBody' opts f t x :> api) = + StreamBody' opts f t x :> SpecialiseToVersion v api + +type instance SpecialiseToVersion v EmptyAPI = EmptyAPI + +type instance + SpecialiseToVersion v (api1 :<|> api2) = + SpecialiseToVersion v api1 :<|> SpecialiseToVersion v api2 diff --git a/libs/wire-api/src/Wire/API/Routes/Versioned.hs b/libs/wire-api/src/Wire/API/Routes/Versioned.hs index be309b77fd..1ca7bac058 100644 --- a/libs/wire-api/src/Wire/API/Routes/Versioned.hs +++ b/libs/wire-api/src/Wire/API/Routes/Versioned.hs @@ -57,6 +57,10 @@ instance route _p ctx d = route (Proxy :: Proxy (ReqBody cts (Versioned v a) :> api)) ctx (fmap (. unVersioned) d) +type instance + SpecialiseToVersion w (VersionedReqBody v cts a :> api) = + VersionedReqBody v cts a :> SpecialiseToVersion w api + instance ( S.ToSchema (Versioned v a), HasSwagger api, diff --git a/libs/wire-api/src/Wire/API/Routes/WebSocket.hs b/libs/wire-api/src/Wire/API/Routes/WebSocket.hs index 756605366a..72354d95bc 100644 --- a/libs/wire-api/src/Wire/API/Routes/WebSocket.hs +++ b/libs/wire-api/src/Wire/API/Routes/WebSocket.hs @@ -31,6 +31,7 @@ import Servant.Server.Internal.Delayed import Servant.Server.Internal.RouteResult import Servant.Server.Internal.Router import Servant.Swagger +import Wire.API.Routes.Version -- | A websocket that relates to a 'PendingConnection' -- Copied and adapted from: @@ -62,6 +63,8 @@ instance HasServer WebSocketPending ctx where errHeaders = mempty } +type instance SpecialiseToVersion v WebSocketPending = WebSocketPending + instance HasSwagger WebSocketPending where toSwagger _ = mempty diff --git a/libs/wire-api/src/Wire/API/VersionInfo.hs b/libs/wire-api/src/Wire/API/VersionInfo.hs index 0fa210b01e..1d05a55e02 100644 --- a/libs/wire-api/src/Wire/API/VersionInfo.hs +++ b/libs/wire-api/src/Wire/API/VersionInfo.hs @@ -42,7 +42,6 @@ import Servant import Servant.Client.Core import Servant.Server.Internal.Delayed import Servant.Server.Internal.DelayedIO -import Servant.Swagger import Wire.API.Routes.ClientAlgebra vinfoObjectSchema :: ValueSchema NamedSwaggerDoc v -> ObjectSchema SwaggerDoc [v] @@ -108,9 +107,6 @@ instance clientWithRoute pm (Proxy @api) req hoistClientMonad pm _ f = hoistClientMonad pm (Proxy @api) f -instance HasSwagger (Until v :> api) where - toSwagger _ = mempty - instance RoutesToPaths api => RoutesToPaths (Until v :> api) where getRoutes = getRoutes @api @@ -159,8 +155,5 @@ instance clientWithRoute pm (Proxy @api) req hoistClientMonad pm _ f = hoistClientMonad pm (Proxy @api) f -instance HasSwagger api => HasSwagger (From v :> api) where - toSwagger _ = toSwagger (Proxy @api) - instance RoutesToPaths api => RoutesToPaths (From v :> api) where getRoutes = getRoutes @api diff --git a/services/brig/src/Brig/API/Public.hs b/services/brig/src/Brig/API/Public.hs index 188db1b0ff..b27c409444 100644 --- a/services/brig/src/Brig/API/Public.hs +++ b/services/brig/src/Brig/API/Public.hs @@ -113,6 +113,7 @@ import Wire.API.Error.Brig qualified as E import Wire.API.Federation.API import Wire.API.Federation.Error import Wire.API.Properties qualified as Public +import Wire.API.Routes.API import Wire.API.Routes.Internal.Brig qualified as BrigInternalAPI import Wire.API.Routes.Internal.Cannon qualified as CannonInternalAPI import Wire.API.Routes.Internal.Cargohold qualified as CargoholdInternalAPI @@ -121,13 +122,13 @@ import Wire.API.Routes.Internal.Spar qualified as SparInternalAPI import Wire.API.Routes.MultiTablePaging qualified as Public import Wire.API.Routes.Named (Named (Named)) import Wire.API.Routes.Public.Brig -import Wire.API.Routes.Public.Brig.OAuth qualified as OAuth -import Wire.API.Routes.Public.Cannon qualified as CannonAPI -import Wire.API.Routes.Public.Cargohold qualified as CargoholdAPI -import Wire.API.Routes.Public.Galley qualified as GalleyAPI -import Wire.API.Routes.Public.Gundeck qualified as GundeckAPI -import Wire.API.Routes.Public.Proxy qualified as ProxyAPI -import Wire.API.Routes.Public.Spar qualified as SparAPI +import Wire.API.Routes.Public.Brig.OAuth +import Wire.API.Routes.Public.Cannon +import Wire.API.Routes.Public.Cargohold +import Wire.API.Routes.Public.Galley +import Wire.API.Routes.Public.Gundeck +import Wire.API.Routes.Public.Proxy +import Wire.API.Routes.Public.Spar import Wire.API.Routes.Public.Util qualified as Public import Wire.API.Routes.Version import Wire.API.SwaggerHelper (cleanupSwagger) @@ -166,17 +167,32 @@ docsAPI = -- -- Dual to `internalEndpointsSwaggerDocsAPI`. versionedSwaggerDocsAPI :: Servant.Server VersionedSwaggerDocsAPI +versionedSwaggerDocsAPI (Just (VersionNumber V5)) = + swaggerSchemaUIServer $ + ( serviceSwagger @VersionAPITag @'V5 + <> serviceSwagger @BrigAPITag @'V5 + <> serviceSwagger @GalleyAPITag @'V5 + <> serviceSwagger @SparAPITag @'V5 + <> serviceSwagger @CargoholdAPITag @'V5 + <> serviceSwagger @CannonAPITag @'V5 + <> serviceSwagger @GundeckAPITag @'V5 + <> serviceSwagger @ProxyAPITag @'V5 + <> serviceSwagger @OAuthAPITag @'V5 + ) + & S.info . S.title .~ "Wire-Server API" + & S.info . S.description ?~ $(embedText =<< makeRelativeToProject "docs/swagger.md") + & cleanupSwagger versionedSwaggerDocsAPI (Just (VersionNumber V4)) = swaggerSchemaUIServer $ - ( brigSwagger - <> versionSwagger - <> GalleyAPI.swaggerDoc - <> SparAPI.swaggerDoc - <> CargoholdAPI.swaggerDoc - <> CannonAPI.swaggerDoc - <> GundeckAPI.swaggerDoc - <> ProxyAPI.swaggerDoc - <> OAuth.swaggerDoc + ( serviceSwagger @VersionAPITag @'V4 + <> serviceSwagger @BrigAPITag @'V4 + <> serviceSwagger @GalleyAPITag @'V4 + <> serviceSwagger @SparAPITag @'V4 + <> serviceSwagger @CargoholdAPITag @'V4 + <> serviceSwagger @CannonAPITag @'V4 + <> serviceSwagger @GundeckAPITag @'V4 + <> serviceSwagger @ProxyAPITag @'V4 + <> serviceSwagger @OAuthAPITag @'V4 ) & S.info . S.title .~ "Wire-Server API" & S.info . S.description ?~ $(embedText =<< makeRelativeToProject "docs/swagger.md") @@ -218,6 +234,11 @@ internalEndpointsSwaggerDocsAPI :: PortNumber -> S.Swagger -> Servant.Server (VersionedSwaggerDocsAPIBase service) +internalEndpointsSwaggerDocsAPI service examplePort swagger (Just (VersionNumber V5)) = + swaggerSchemaUIServer $ + swagger + & adjustSwaggerForInternalEndpoint service examplePort + & cleanupSwagger internalEndpointsSwaggerDocsAPI service examplePort swagger (Just (VersionNumber V4)) = swaggerSchemaUIServer $ swagger diff --git a/services/brig/test/integration/API/Swagger.hs b/services/brig/test/integration/API/Swagger.hs index 2d2525dcdc..ec5ec230e9 100644 --- a/services/brig/test/integration/API/Swagger.hs +++ b/services/brig/test/integration/API/Swagger.hs @@ -48,7 +48,7 @@ tests p _opts brigNoImplicitVersion = [ test p "toc" $ do forM_ ["/api/swagger-ui", "/api/swagger-ui/index.html", "/api/swagger.json"] $ \pth -> do r <- get (brigNoImplicitVersion . path pth . expect2xx) - liftIO $ assertEqual "toc is intact" (responseBody r) (Just "

please pick an api version

/v0/api/swagger-ui/
/v1/api/swagger-ui/
/v2/api/swagger-ui/
/v3/api/swagger-ui/
/v4/api/swagger-ui/
") + liftIO $ assertEqual "toc is intact" (Just "

please pick an api version

/v0/api/swagger-ui/
/v1/api/swagger-ui/
/v2/api/swagger-ui/
/v3/api/swagger-ui/
/v4/api/swagger-ui/
/v5/api/swagger-ui/
") (responseBody r) -- are all versions listed? forM_ [minBound :: Version ..] $ \v -> liftIO $ assertBool (show v) ((cs (toQueryParam v) :: String) `isInfixOf` (cs . fromJust . responseBody $ r)) -- FUTUREWORK: maybe test that no invalid versions are listed? (that wouldn't diff --git a/services/cannon/src/Cannon/API/Public.hs b/services/cannon/src/Cannon/API/Public.hs index 0eb81bf5fb..4a559f9f17 100644 --- a/services/cannon/src/Cannon/API/Public.hs +++ b/services/cannon/src/Cannon/API/Public.hs @@ -31,7 +31,7 @@ import Servant import Wire.API.Routes.Named import Wire.API.Routes.Public.Cannon -publicAPIServer :: ServerT PublicAPI Cannon +publicAPIServer :: ServerT CannonAPI Cannon publicAPIServer = Named @"await-notifications" streamData streamData :: UserId -> ConnId -> Maybe ClientId -> PendingConnection -> Cannon () diff --git a/services/cannon/src/Cannon/Run.hs b/services/cannon/src/Cannon/Run.hs index df5f6e06a6..b0657c59f8 100644 --- a/services/cannon/src/Cannon/Run.hs +++ b/services/cannon/src/Cannon/Run.hs @@ -58,7 +58,7 @@ import Wire.API.Routes.Internal.Cannon qualified as Internal import Wire.API.Routes.Public.Cannon import Wire.API.Routes.Version.Wai -type CombinedAPI = PublicAPI :<|> Internal.API +type CombinedAPI = CannonAPI :<|> Internal.API run :: Opts -> IO () run o = do @@ -88,7 +88,7 @@ run o = do app = middleware (serve (Proxy @CombinedAPI) server) server :: Servant.Server CombinedAPI server = - hoistServer (Proxy @PublicAPI) (runCannonToServant e) publicAPIServer + hoistServer (Proxy @CannonAPI) (runCannonToServant e) publicAPIServer :<|> hoistServer (Proxy @Internal.API) (runCannonToServant e) internalServer tid <- myThreadId E.handle uncaughtExceptionHandler $ do diff --git a/services/cargohold/src/CargoHold/API/Public.hs b/services/cargohold/src/CargoHold/API/Public.hs index 280e00b02b..a896025bdc 100644 --- a/services/cargohold/src/CargoHold/API/Public.hs +++ b/services/cargohold/src/CargoHold/API/Public.hs @@ -41,7 +41,7 @@ import Wire.API.Routes.AssetBody import Wire.API.Routes.Internal.Cargohold import Wire.API.Routes.Public.Cargohold -servantSitemap :: ServerT ServantAPI Handler +servantSitemap :: ServerT CargoholdAPI Handler servantSitemap = renewTokenV3 :<|> deleteTokenV3 diff --git a/services/cargohold/src/CargoHold/Run.hs b/services/cargohold/src/CargoHold/Run.hs index 556cabf367..ae43e1e96a 100644 --- a/services/cargohold/src/CargoHold/Run.hs +++ b/services/cargohold/src/CargoHold/Run.hs @@ -55,7 +55,7 @@ import Wire.API.Routes.Internal.Cargohold import Wire.API.Routes.Public.Cargohold import Wire.API.Routes.Version.Wai -type CombinedAPI = FederationAPI :<|> ServantAPI :<|> InternalAPI +type CombinedAPI = FederationAPI :<|> CargoholdAPI :<|> InternalAPI run :: Opts -> IO () run o = lowerCodensity $ do @@ -89,7 +89,7 @@ mkApp o = Codensity $ \k -> (Proxy @CombinedAPI) ((o ^. settings . federationDomain) :. Servant.EmptyContext) ( hoistServerWithDomain @FederationAPI (toServantHandler e) federationSitemap - :<|> hoistServerWithDomain @ServantAPI (toServantHandler e) servantSitemap + :<|> hoistServerWithDomain @CargoholdAPI (toServantHandler e) servantSitemap :<|> hoistServerWithDomain @InternalAPI (toServantHandler e) internalSitemap ) r diff --git a/services/galley/src/Galley/API/Public/Servant.hs b/services/galley/src/Galley/API/Public/Servant.hs index 86e223c522..ea777ec499 100644 --- a/services/galley/src/Galley/API/Public/Servant.hs +++ b/services/galley/src/Galley/API/Public/Servant.hs @@ -32,7 +32,7 @@ import Galley.App import Wire.API.Routes.API import Wire.API.Routes.Public.Galley -servantSitemap :: API ServantAPI GalleyEffects +servantSitemap :: API GalleyAPI GalleyEffects servantSitemap = conversationAPI <@> teamConversationAPI diff --git a/services/galley/src/Galley/Run.hs b/services/galley/src/Galley/Run.hs index bd2ad81994..60924f451f 100644 --- a/services/galley/src/Galley/Run.hs +++ b/services/galley/src/Galley/Run.hs @@ -63,7 +63,7 @@ import System.Logger qualified as Log import System.Logger.Extended (mkLogger) import Util.Options import Wire.API.Routes.API -import Wire.API.Routes.Public.Galley qualified as GalleyAPI +import Wire.API.Routes.Public.Galley import Wire.API.Routes.Version.Wai run :: Opts -> IO () @@ -151,7 +151,7 @@ bodyParserErrorFormatter' _ _ errMsg = } type CombinedAPI = - GalleyAPI.ServantAPI + GalleyAPI :<|> InternalAPI :<|> FederationAPI :<|> Servant.Raw diff --git a/services/spar/src/Spar/API.hs b/services/spar/src/Spar/API.hs index 5c27ad4407..4107e44910 100644 --- a/services/spar/src/Spar/API.hs +++ b/services/spar/src/Spar/API.hs @@ -32,7 +32,7 @@ module Spar.API api, -- * API types - API, + SparAPI, -- ** Individual API pieces APIAuthReqPrecheck, @@ -113,7 +113,7 @@ import qualified Wire.Sem.Random as Random app :: Env -> Application app ctx = SAML.setHttpCachePolicy $ - serve (Proxy @API) (hoistServer (Proxy @API) (runSparToHandler ctx) (api $ sparCtxOpts ctx) :: Server API) + serve (Proxy @SparAPI) (hoistServer (Proxy @SparAPI) (runSparToHandler ctx) (api $ sparCtxOpts ctx) :: Server SparAPI) api :: ( Member GalleyAccess r, @@ -144,7 +144,7 @@ api :: Member (Logger (Msg -> Msg)) r ) => Opts -> - ServerT API (Sem r) + ServerT SparAPI (Sem r) api opts = apiSSO opts :<|> apiIDP diff --git a/services/spar/src/Spar/Run.hs b/services/spar/src/Spar/Run.hs index 58681ad897..5331fddabc 100644 --- a/services/spar/src/Spar/Run.hs +++ b/services/spar/src/Spar/Run.hs @@ -44,7 +44,7 @@ import qualified Network.Wai.Handler.Warp as Warp import Network.Wai.Utilities.Request (lookupRequestId) import qualified Network.Wai.Utilities.Server as WU import qualified SAML2.WebSSO as SAML -import Spar.API (API, app) +import Spar.API (SparAPI, app) import Spar.App import qualified Spar.Data as Data import Spar.Data.Instances () @@ -116,7 +116,7 @@ mkApp sparCtxOpts = do let wrappedApp = versionMiddleware (fold (disabledAPIVersions sparCtxOpts)) . WU.heavyDebugLogging heavyLogOnly logLevel sparCtxLogger - . servantPrometheusMiddleware (Proxy @API) + . servantPrometheusMiddleware (Proxy @SparAPI) . WU.catchErrors sparCtxLogger [] -- Error 'Response's are usually not thrown as exceptions, but logged in -- 'renderSparErrorWithLogging' before the 'Application' can construct a 'Response' diff --git a/services/spar/test/Test/Spar/APISpec.hs b/services/spar/test/Test/Spar/APISpec.hs index ceefb59e48..07bfdb8fde 100644 --- a/services/spar/test/Test/Spar/APISpec.hs +++ b/services/spar/test/Test/Spar/APISpec.hs @@ -37,9 +37,9 @@ import Wire.API.User.Saml (SsoSettings) spec :: Spec spec = do -- Note: SCIM types are not validated because their content-type is 'SCIM'. - validateEveryToJSON (Proxy @API.API) + validateEveryToJSON (Proxy @API.SparAPI) it "api consistency" $ do - pathsConsistencyCheck (routesToPaths @API.API) `shouldBe` mempty + pathsConsistencyCheck (routesToPaths @API.SparAPI) `shouldBe` mempty it "roundtrip: IdPMetadataInfo" . property $ \(val :: IdPMetadataInfo) -> do let withoutRaw (IdPMetadataValue _ x) = x (withoutRaw <$> (Aeson.eitherDecode . Aeson.encode) val) `shouldBe` Right (withoutRaw val) diff --git a/tools/fedcalls/src/Main.hs b/tools/fedcalls/src/Main.hs index 79ac0e7887..c1b4471da9 100644 --- a/tools/fedcalls/src/Main.hs +++ b/tools/fedcalls/src/Main.hs @@ -42,17 +42,16 @@ import Data.Swagger ) import Imports import Language.Dot as D +import Wire.API.Routes.API import Wire.API.Routes.Internal.Brig qualified as BrigIRoutes -import Wire.API.Routes.Public.Brig qualified as BrigRoutes -import Wire.API.Routes.Public.Cannon qualified as CannonRoutes -import Wire.API.Routes.Public.Cargohold qualified as CargoholdRoutes -import Wire.API.Routes.Public.Galley qualified as GalleyRoutes -import Wire.API.Routes.Public.Gundeck qualified as GundeckRoutes -import Wire.API.Routes.Public.Proxy qualified as ProxyRoutes --- import qualified Wire.API.Routes.Internal.Cannon as CannonIRoutes --- import qualified Wire.API.Routes.Internal.Cargohold as CargoholdIRoutes --- import qualified Wire.API.Routes.Internal.LegalHold as LegalHoldIRoutes -import Wire.API.Routes.Public.Spar qualified as SparRoutes +import Wire.API.Routes.Public.Brig +import Wire.API.Routes.Public.Cannon +import Wire.API.Routes.Public.Cargohold +import Wire.API.Routes.Public.Galley +import Wire.API.Routes.Public.Gundeck +import Wire.API.Routes.Public.Proxy +import Wire.API.Routes.Public.Spar +import Wire.API.Routes.Version ------------------------------ @@ -72,13 +71,13 @@ swaggers = -- services, use that in /services/brig/src/Brig/API/Public.hs instead of -- doing it by hand. - BrigRoutes.brigSwagger, -- TODO: s/brigSwagger/swaggerDoc/ like everybody else! - CannonRoutes.swaggerDoc, - CargoholdRoutes.swaggerDoc, - GalleyRoutes.swaggerDoc, - GundeckRoutes.swaggerDoc, - ProxyRoutes.swaggerDoc, - SparRoutes.swaggerDoc, + serviceSwagger @BrigAPITag @'V5, + serviceSwagger @CannonAPITag @'V5, + serviceSwagger @CargoholdAPITag @'V5, + serviceSwagger @GalleyAPITag @'V5, + serviceSwagger @GundeckAPITag @'V5, + serviceSwagger @ProxyAPITag @'V5, + serviceSwagger @SparAPITag @'V5, -- TODO: collect all internal apis somewhere else (brig?), and expose them -- via an internal swagger api end-point.