diff --git a/.changeset/heavy-badgers-jog.md b/.changeset/heavy-badgers-jog.md new file mode 100644 index 000000000..e4764a07e --- /dev/null +++ b/.changeset/heavy-badgers-jog.md @@ -0,0 +1,8 @@ +--- +"@logto/core": patch +--- + +fix OpenAPI schema returned by the `GET /api/swagger.json` endpoint + +1. The `:` character is invalid in parameter names, such as `organizationId:root`. These characters have been replaced with `-`. +2. The `tenantId` parameter of the `/api/.well-known/endpoints/{tenantId}` route was missing from the generated OpenAPI spec document, resulting in validation errors. This has been fixed. diff --git a/packages/core/src/routes/swagger/index.test.ts b/packages/core/src/routes/swagger/index.test.ts index 769a64fe5..7444f2d67 100644 --- a/packages/core/src/routes/swagger/index.test.ts +++ b/packages/core/src/routes/swagger/index.test.ts @@ -120,7 +120,7 @@ describe('GET /swagger.json', () => { get: { parameters: [ { - $ref: '#/components/parameters/mockId:root', + $ref: '#/components/parameters/mockId-root', }, { name: 'field', @@ -135,7 +135,7 @@ describe('GET /swagger.json', () => { get: { parameters: [ { - $ref: '#/components/parameters/mockId:root', + $ref: '#/components/parameters/mockId-root', }, { name: 'field', diff --git a/packages/core/src/routes/swagger/index.ts b/packages/core/src/routes/swagger/index.ts index 94bb7fc4a..b8ab38b45 100644 --- a/packages/core/src/routes/swagger/index.ts +++ b/packages/core/src/routes/swagger/index.ts @@ -35,6 +35,7 @@ import { paginationParameters, buildPathIdParameters, mergeParameters, + customParameters, } from './utils/parameters.js'; type RouteObject = { @@ -242,8 +243,11 @@ export default function swaggerRoutes ({ ...previous, ...buildPathIdParameters(entityName) }), - {} + (previous, entityName) => ({ + ...previous, + ...buildPathIdParameters(entityName), + }), + customParameters() ), }, tags: [...tags, ...additionalTags].map((tag) => ({ name: tag })), diff --git a/packages/core/src/routes/swagger/utils/parameters.ts b/packages/core/src/routes/swagger/utils/parameters.ts index 49bbd20a6..a3bccbc50 100644 --- a/packages/core/src/routes/swagger/utils/parameters.ts +++ b/packages/core/src/routes/swagger/utils/parameters.ts @@ -48,7 +48,7 @@ type BuildParameters = { * For path parameters, this function will try to match reusable ID parameters: * * - If the parameter name is `id`, and the path is `/organizations/{id}/users`, the parameter - * `id` will be a reference to `#/components/parameters/organizationId:root`. + * `id` will be a reference to `#/components/parameters/organizationId-root`. * - If the parameter name ends with `Id`, and the path is `/organizations/{id}/users/{userId}`, * the parameter `userId` will be a reference to `#/components/parameters/userId`. * @@ -91,7 +91,7 @@ export const buildParameters: BuildParameters = ( if (key === 'id') { if (rootComponent) { return { - $ref: `#/components/parameters/${pluralize(rootComponent, 1)}Id:root`, + $ref: `#/components/parameters/${pluralize(rootComponent, 1)}Id-root`, }; } @@ -206,7 +206,7 @@ export const mergeParameters = (destination: unknown[], source: unknown[]) => { * type: 'string', * }, * }, - * 'organizationId:root': { + * 'organizationId-root': { * name: 'id', * // ... same as above * }, @@ -216,7 +216,7 @@ export const mergeParameters = (destination: unknown[], source: unknown[]) => { * @remarks * The root path component is the first path component in the path. For example, the root path * component of `/organizations/{id}/users` is `organizations`. Since the name of the parameter is - * same for all root path components, we need to add an additional key with the `:root` suffix to + * same for all root path components, we need to add an additional key with the `-root` suffix to * distinguish them. * * @param rootComponent The root path component in kebab case (`foo-bar`). @@ -241,7 +241,7 @@ export const buildPathIdParameters = ( // Need to duplicate the object because OpenAPI does not support partial reference. // See https://github.com/OAI/OpenAPI-Specification/issues/2026 return { - [`${entityId}:root`]: { + [`${entityId}-root`]: { ...shared, name: 'id', }, @@ -251,3 +251,20 @@ export const buildPathIdParameters = ( }, }; }; + +/** + * Build a parameter object with additional parameters that are not inferred from the path. + */ +export const customParameters = (): Record => { + return Object.freeze({ + tenantId: { + name: 'tenantId', + in: 'path', + description: 'The unique identifier of the tenant.', + required: true, + schema: { + type: 'string', + }, + }, + }); +};