Skip to content

feat: support arrays of global prefixes in documents and UI mounting - #4131

Open
alireza-aminzadeh wants to merge 1 commit into
nestjs:masterfrom
alireza-aminzadeh:feat/multi-global-prefix-swagger
Open

alireza-aminzadeh wants to merge 1 commit into
nestjs:masterfrom
alireza-aminzadeh:feat/multi-global-prefix-swagger

Conversation

@alireza-aminzadeh

Copy link
Copy Markdown

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Other... Please describe:

What is the current behavior?

@nestjs/core is gaining support for registering more than one global prefix in a single call, e.g. app.setGlobalPrefix(['api', 'v1']) (see nestjs/nest#17713). Today, @nestjs/swagger only ever looks at the first/only global prefix:

  • SwaggerScanner / SwaggerExplorer build every route against a single prefix, so routes end up missing from the generated OpenAPI document under any additional prefixes.
  • SwaggerModule.setup() only mounts the UI and JSON/YAML documents under the first prefix, so they are unreachable under the others.

Issue Number: N/A (follow-up to nestjs/nest#17713, discussed with @micalevisk in that PR's thread)

What is the new behavior?

  • Added a getGlobalPrefixes() helper next to the existing getGlobalPrefix(). It reads ApplicationConfig#getGlobalPrefixes() when available (upcoming @nestjs/core) and falls back to the current single-prefix getter otherwise, so it works against both today's and the upcoming @nestjs/core release.
  • SwaggerScanner / SwaggerExplorer now build each route once per configured global prefix instead of once overall. RoutePathFactory#create() is still invoked with a single prefix per call (not the whole array), so this does not require @nestjs/core to have its own multi-prefix fan-out yet.
    • Exact method + path duplicates across prefixes collapse back into a single entry.
    • A numeric suffix is appended to operationId on repeat occurrences so the document keeps a unique id per operation, per the OpenAPI Specification.
  • SwaggerModule.setup() mounts the UI and JSON/YAML definitions once per prefix when useGlobalPrefix is enabled (e.g. under both /api/docs and /v1/docs) instead of only the first one. The document/factory is still only built at most once and shared across every mount point.

Applications using a single global prefix (or none) are unaffected: every code path above only branches into the new per-prefix behavior once an array with more than one prefix is actually present. Existing single-prefix output is byte-for-byte identical to before.

Tests

  • New unit tests for getGlobalPrefix / getGlobalPrefixes in test/utils/get-global-prefix.spec.ts.
  • Extended unit tests in test/explorer/swagger-explorer.spec.ts covering multi-prefix path generation, operationId disambiguation, single-element array equivalence, and duplicate-prefix collapsing.
  • New e2e test in e2e/express.e2e-spec.ts verifying SwaggerModule.setup() correctly serves the UI, JSON and YAML documents under multiple prefixes on a real NestExpressApplication.

Does this PR introduce a breaking change?

  • Yes
  • No

No public API changes. globalPrefix in the relevant internal option objects is now typed as string | string[] | undefined instead of string | undefined, but this is an internal/unexported interface, and existing single-string input still behaves exactly as before.

Other information

This is a follow-up to the multi-prefix work being discussed in nestjs/nest#17713. @micalevisk suggested opening a companion PR here for @nestjs/swagger once that lands, since the document generator and UI mounting would otherwise be unaware of any additional prefixes.

`@nestjs/core` is gaining the ability to register more than one global
prefix in a single call (`app.setGlobalPrefix(['api', 'v1'])`, see
nestjs/nest#17713). Until now this package only ever looked at the
first/only prefix, so applications using several prefixes ended up with
routes missing from the generated document, and the Swagger UI / JSON /
YAML definitions reachable under just one of them.

- Add `getGlobalPrefixes()` next to the existing `getGlobalPrefix()`
  helper. It reads `ApplicationConfig#getGlobalPrefixes()` when
  available and falls back to the older single-prefix getter otherwise,
  so it works against both current and upcoming `@nestjs/core`
  releases.

- `SwaggerScanner`/`SwaggerExplorer` now build each route once per
  configured prefix instead of once overall. `RoutePathFactory#create()`
  is still called with a single prefix at a time, rather than
  forwarding the whole array in one go, so this does not depend on
  `@nestjs/core` having its own multi-prefix fan-out yet. Exact
  `method`+`path` duplicates (e.g. a route excluded from every prefix)
  collapse back into a single entry, and a numeric suffix is appended
  to `operationId` on repeat occurrences so the document keeps a unique
  id per operation, per the OpenAPI Specification. The first prefix's
  output is left untouched in every case, so single-prefix (or
  no-prefix) applications keep generating byte-for-byte identical
  documents.

- `SwaggerModule.setup()` mounts the UI and JSON/YAML definitions once
  per prefix when `useGlobalPrefix` is enabled (e.g. under both
  `/api/docs` and `/v1/docs`) instead of only the first one. The
  document/factory passed in is still only built at most once and
  shared across every mount point.

Applications using a single global prefix (or none) are unaffected:
every path above only branches into the new per-prefix behavior once an
array with more than one prefix is actually present.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant