Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Render one Swagger page per internal endpoint. This superseeds the previous Swagger docs page for all internal endpoints.
4 changes: 0 additions & 4 deletions charts/nginz/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,6 @@ nginx_conf:
disable_zauth: true
envs:
- staging
- path: /api-internal/swagger.json$
disable_zauth: true
envs:
- all
- path: /api-internal/swagger-ui
disable_zauth: true
envs:
Expand Down
49 changes: 37 additions & 12 deletions docs/src/understand/api-client-perspective/swagger.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,19 @@ docs.

### Public endpoints
- Version `v0`:
- [new staging swagger page - **public**
endpoints](https://staging-nginz-https.zinfra.io/v0/api/swagger-ui/)
- [**public**
endpoints](https://staging-nginz-https.zinfra.io/v0/api/swagger-ui/)
- Version `v1`:
- [new staging swagger page - **public**
- [**public**
endpoints](https://staging-nginz-https.zinfra.io/v1/api/swagger-ui/)
- Version `v2`:
- [new staging swagger page - **public**
- [**public**
endpoints](https://staging-nginz-https.zinfra.io/v2/api/swagger-ui/)
- Version `v3`:
- [new staging swagger page - **public**
- [**public**
endpoints](https://staging-nginz-https.zinfra.io/v3/api/swagger-ui/)
- Unversioned
- [new staging swagger page - **public**
- Unversioned:
- [**public**
endpoints](https://staging-nginz-https.zinfra.io/api/swagger-ui/)

The first part of the URL's path is the version. No specified version means
Expand Down Expand Up @@ -65,12 +65,37 @@ The URL to open in your browser for the development version `3` is
`https://staging-nginz-https.zinfra.io/v3/api/swagger-ui/`.

### Internal endpoints

Swagger docs for internal endpoints are served per service. I.e. there's one for
`brig`, one for `cannon`, etc.. This is because Swagger doesn't play well with
multiple actions having the same combination of HTTP method and URL path.

- Version `v3`:
- [new staging swagger page - **internal** (private)
endpoints](https://staging-nginz-https.zinfra.io/v3/api-internal/swagger-ui/)
- Unversioned
- [new staging swagger page - **internal** (private)
endpoints](https://staging-nginz-https.zinfra.io/api-internal/swagger-ui/)
- [`brig` - **internal** (private)
endpoints](https://staging-nginz-https.zinfra.io/v3/api-internal/swagger-ui/brig)
- [`cannon` - **internal** (private)
endpoints](https://staging-nginz-https.zinfra.io/v3/api-internal/swagger-ui/cannon)
- [`cargohold` - **internal** (private)
endpoints](https://staging-nginz-https.zinfra.io/v3/api-internal/swagger-ui/cargohold)
- [`galley` - **internal** (private)
endpoints](https://staging-nginz-https.zinfra.io/v3/api-internal/swagger-ui/galley)
- [`legalhold` - **internal** (private)
endpoints](https://staging-nginz-https.zinfra.io/v3/api-internal/swagger-ui/legalhold)
- [`spar` - **internal** (private)
endpoints](https://staging-nginz-https.zinfra.io/v3/api-internal/swagger-ui/spar)
- Unversioned:
- [`brig` - **internal** (private)
endpoints](https://staging-nginz-https.zinfra.io/api-internal/swagger-ui/brig)
- [`cannon` - **internal** (private)
endpoints](https://staging-nginz-https.zinfra.io/api-internal/swagger-ui/cannon)
- [`cargohold` - **internal** (private)
endpoints](https://staging-nginz-https.zinfra.io/api-internal/swagger-ui/cargohold)
- [`galley` - **internal** (private)
endpoints](https://staging-nginz-https.zinfra.io/api-internal/swagger-ui/galley)
- [`legalhold` - **internal** (private)
endpoints](https://staging-nginz-https.zinfra.io/api-internal/swagger-ui/legalhold)
- [`spar` - **internal** (private)
endpoints](https://staging-nginz-https.zinfra.io/api-internal/swagger-ui/spar)

The URL pattern is similar to that of public endpoints:
`https://<nginz-host>/v<version>/api-internal/swagger-ui/`. No specified version
Expand Down
4 changes: 1 addition & 3 deletions libs/wire-api/src/Wire/API/Routes/Internal/Brig.hs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ import Wire.API.Routes.Internal.Brig.EJPD
import qualified Wire.API.Routes.Internal.Galley.TeamFeatureNoConfigMulti as Multi
import Wire.API.Routes.MultiVerb
import Wire.API.Routes.Named
import Wire.API.SwaggerServant
import Wire.API.Team.Feature
import Wire.API.User
import Wire.API.User.Auth
Expand Down Expand Up @@ -318,8 +317,7 @@ type GetVerificationCode =
:> Get '[Servant.JSON] (Maybe Code.Value)

type API =
SwaggerTag "brig"
:> "i"
"i"
:> ( EJPD_API
:<|> AccountAPI
:<|> MLSAPI
Expand Down
4 changes: 1 addition & 3 deletions libs/wire-api/src/Wire/API/Routes/Internal/Cannon.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@ import Wire.API.Internal.BulkPush
import Wire.API.RawJson
import Wire.API.Routes.MultiVerb
import Wire.API.Routes.Named
import Wire.API.SwaggerServant

type API =
SwaggerTag "cannon"
:> "i"
"i"
:> ( Named
"get-status"
( "status"
Expand Down
4 changes: 1 addition & 3 deletions libs/wire-api/src/Wire/API/Routes/Internal/Cargohold.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@ import Imports
import Servant
import Servant.Swagger
import Wire.API.Routes.MultiVerb
import Wire.API.SwaggerServant

type InternalAPI =
SwaggerTag "cargohold"
:> "i"
"i"
:> "status"
:> MultiVerb 'GET '() '[RespondEmpty 200 "OK"] ()

Expand Down
3 changes: 1 addition & 2 deletions libs/wire-api/src/Wire/API/Routes/Internal/Galley.hs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import Wire.API.Routes.Named
import Wire.API.Routes.Public
import Wire.API.Routes.Public.Galley.Conversation
import Wire.API.Routes.Public.Galley.Feature
import Wire.API.SwaggerServant
import Wire.API.Team
import Wire.API.Team.Feature
import Wire.API.Team.Member
Expand Down Expand Up @@ -166,7 +165,7 @@ type IFeatureAPI =
:> Get '[Servant.JSON] AllFeatureConfigs
)

type InternalAPI = SwaggerTag "galley" :> "i" :> InternalAPIBase
type InternalAPI = "i" :> InternalAPIBase

type InternalAPIBase =
Named
Expand Down
4 changes: 1 addition & 3 deletions libs/wire-api/src/Wire/API/Routes/Internal/LegalHold.hs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,10 @@ import Data.Swagger
import Imports
import Servant.API hiding (Header, WithStatus)
import Servant.Swagger
import Wire.API.SwaggerServant
import Wire.API.Team.Feature

type InternalLegalHoldAPI =
SwaggerTag "legalhold"
:> "i"
"i"
:> "teams"
:> ( Capture "tid" TeamId
:> "legalhold"
Expand Down
4 changes: 1 addition & 3 deletions libs/wire-api/src/Wire/API/Routes/Internal/Spar.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,11 @@ import Data.Swagger
import Imports
import Servant
import Servant.Swagger
import Wire.API.SwaggerServant
import Wire.API.User
import Wire.API.User.Saml

type InternalAPI =
SwaggerTag "spar"
:> "i"
"i"
:> ( "status" :> Get '[JSON] NoContent
:<|> "teams" :> Capture "team" TeamId :> DeleteNoContent
:<|> "sso" :> "settings" :> ReqBody '[JSON] SsoSettings :> Put '[JSON] NoContent
Expand Down
74 changes: 1 addition & 73 deletions libs/wire-api/src/Wire/API/SwaggerServant.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,88 +17,16 @@

-- | Servant combinators related to Swagger docs
module Wire.API.SwaggerServant
( SwaggerTag,
OmitDocs,
( OmitDocs,
)
where

import Control.Lens
import qualified Data.HashMap.Strict.InsOrd as InsOrdMap
import qualified Data.HashSet.InsOrd as InsOrdSet
import Data.Metrics.Servant
import Data.Proxy
import Data.Swagger (allOperations)
import qualified Data.Swagger as S
import Data.Text as T
import GHC.TypeLits
import Imports hiding (head)
import Servant
import Servant.Client.Core
import Servant.Swagger (HasSwagger (toSwagger))

-- | Add tag @tag@ to endpoints
--
-- @tag@ is a type level string. In swagger terms this combinator adds a
-- `Data.Swagger.Internal.TagName` to all `Data.Swagger.Internal.Operation`s
-- it's applied to. Tags are rendered as sections in swagger doc.
--
-- @
-- SwaggerTag "cannon"
-- :> "i"
-- :> ( Named
-- "get-status"
-- ( "status"
-- :> MultiVerb
-- 'GET
-- '[PlainText]
-- '[RespondEmpty 200 "Service is alive."]
-- ()
-- )
-- @
data SwaggerTag tag

-- | Adjust `Swagger` according to its `SwaggerTag`
--
-- Unfortunately, paths are stored as keys in a `InsOrdMap.InsOrdHashMap`.
-- Because those have to be unique, prefix them with the @tag@ (service name.)
-- Otherwise, the `Monoid` instance of `Swagger.Swagger` would throw duplicated
-- paths away. The @tag@ is also used as a `Swagger.TagName` for all
-- `Swagger.Operations`.
instance (HasSwagger b, KnownSymbol tag) => HasSwagger (SwaggerTag tag :> b) where
toSwagger _ = tagSwagger $ toSwagger (Proxy :: Proxy b)
where
tagString :: String
tagString = symbolVal (Proxy @tag)

tagSwagger :: S.Swagger -> S.Swagger
tagSwagger s =
s
& S.paths .~ tagPaths s
& allOperations . S.tags <>~ tag

tag :: InsOrdSet.InsOrdHashSet S.TagName
tag = InsOrdSet.singleton @S.TagName (T.pack tagString)

tagPaths :: S.Swagger -> InsOrdMap.InsOrdHashMap FilePath S.PathItem
tagPaths s =
let m = s ^. S.paths
in InsOrdMap.mapKeys (\k -> "/<" ++ tagString ++ ">" ++ k) m

instance HasServer api ctx => HasServer (SwaggerTag tag :> api) ctx where
type ServerT (SwaggerTag tag :> api) m = ServerT api m

route _ = route (Proxy :: Proxy api)
hoistServerWithContext _ pc nt s =
hoistServerWithContext (Proxy :: Proxy api) pc nt s

instance RoutesToPaths api => RoutesToPaths (SwaggerTag tag :> api) where
getRoutes = getRoutes @api

instance HasClient m api => HasClient m (SwaggerTag tag :> api) where
type Client m (SwaggerTag tag :> api) = Client m api
clientWithRoute proxyM _ = clientWithRoute proxyM (Proxy @api)
hoistClientMonad proxyM _ = hoistClientMonad proxyM (Proxy @api)

-- | A type-level tag that lets us omit any branch from Swagger docs.
--
-- FUTUREWORK(fisx): this is currently only used for the spar internal api
Expand Down
12 changes: 0 additions & 12 deletions services/brig/docs/swagger-internal-endpoints.md

This file was deleted.

47 changes: 22 additions & 25 deletions services/brig/src/Brig/API/Public.hs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ import qualified Data.ZAuth.Token as ZAuth
import FileEmbedLzma
import Galley.Types.Teams (HiddenPerm (..), hasPermission)
import Imports hiding (head)
import Network.Socket (PortNumber)
import Network.Wai.Routing
import Network.Wai.Utilities as Utilities
import Polysemy
Expand All @@ -112,7 +113,6 @@ import qualified Wire.API.Routes.Internal.Brig as BrigInternalAPI
import qualified Wire.API.Routes.Internal.Cannon as CannonInternalAPI
import qualified Wire.API.Routes.Internal.Cargohold as CargoholdInternalAPI
import qualified Wire.API.Routes.Internal.Galley as GalleyInternalAPI
import qualified Wire.API.Routes.Internal.LegalHold as LegalHoldInternalAPI
import qualified Wire.API.Routes.Internal.Spar as SparInternalAPI
import qualified Wire.API.Routes.MultiTablePaging as Public
import Wire.API.Routes.Named (Named (Named))
Expand Down Expand Up @@ -147,7 +147,14 @@ import Wire.Sem.Now (Now)
-- User API -----------------------------------------------------------

docsAPI :: Servant.Server DocsAPI
docsAPI = versionedSwaggerDocsAPI :<|> pure eventNotificationSchemas :<|> internalEndpointsSwaggerDocsAPI
docsAPI =
versionedSwaggerDocsAPI
:<|> pure eventNotificationSchemas
:<|> internalEndpointsSwaggerDocsAPI "brig" 9082 BrigInternalAPI.swaggerDoc
:<|> internalEndpointsSwaggerDocsAPI "cannon" 9093 CannonInternalAPI.swaggerDoc
:<|> internalEndpointsSwaggerDocsAPI "cargohold" 9094 CargoholdInternalAPI.swaggerDoc
:<|> internalEndpointsSwaggerDocsAPI "galley" 9095 GalleyInternalAPI.swaggerDoc
:<|> internalEndpointsSwaggerDocsAPI "spar" 9098 SparInternalAPI.swaggerDoc

-- | Serves Swagger docs for public endpoints
--
Expand Down Expand Up @@ -178,31 +185,21 @@ versionedSwaggerDocsAPI Nothing = versionedSwaggerDocsAPI (Just maxBound)
-- empty. It would have been too tedious to create them. Please add
-- pre-generated docs on version increase as it's done in
-- `versionedSwaggerDocsAPI`.
internalEndpointsSwaggerDocsAPI :: Servant.Server InternalEndpointsSwaggerDocsAPI
internalEndpointsSwaggerDocsAPI (Just V3) =
internalEndpointsSwaggerDocsAPI ::
String ->
PortNumber ->
S.Swagger ->
Servant.Server (VersionedSwaggerDocsAPIBase service)
internalEndpointsSwaggerDocsAPI service examplePort swagger (Just V3) =
swaggerSchemaUIServer $
( BrigInternalAPI.swaggerDoc
<> CannonInternalAPI.swaggerDoc
<> CargoholdInternalAPI.swaggerDoc
<> LegalHoldInternalAPI.swaggerDoc
<> GalleyInternalAPI.swaggerDoc
<> SparInternalAPI.swaggerDoc
)
& S.info . S.title .~ "Wire-Server internal API"
& S.info . S.description ?~ $(embedText =<< makeRelativeToProject "docs/swagger-internal-endpoints.md")
swagger
& adjustSwaggerForInternalEndpoint service examplePort
& cleanupSwagger
internalEndpointsSwaggerDocsAPI (Just V0) = emptySwagger
internalEndpointsSwaggerDocsAPI (Just V1) = emptySwagger
internalEndpointsSwaggerDocsAPI (Just V2) = emptySwagger
internalEndpointsSwaggerDocsAPI Nothing = internalEndpointsSwaggerDocsAPI (Just maxBound)

emptySwagger :: Servant.Server VersionedSwaggerDocsAPIBase
emptySwagger =
swaggerSchemaUIServer $
mempty @S.Swagger
& S.info . S.title .~ "Wire-Server internal API"
& S.info . S.description
?~ "There is no Swagger documentation for this version. Please refer to v3 or later."
internalEndpointsSwaggerDocsAPI _ _ _ (Just V0) = emptySwagger
internalEndpointsSwaggerDocsAPI _ _ _ (Just V1) = emptySwagger
internalEndpointsSwaggerDocsAPI _ _ _ (Just V2) = emptySwagger
internalEndpointsSwaggerDocsAPI service examplePort swagger Nothing =
internalEndpointsSwaggerDocsAPI service examplePort swagger (Just maxBound)

servantSitemap ::
forall r p.
Expand Down
Loading