0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

Merge pull request #6089 from mostafa/fix-oas-validation-errors

fix: generate valid OpenAPI spec
This commit is contained in:
Gao Sun 2024-06-23 14:12:20 +08:00 committed by GitHub
commit a43434c42f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 38 additions and 9 deletions

View file

@ -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.

View file

@ -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',

View file

@ -35,6 +35,7 @@ import {
paginationParameters,
buildPathIdParameters,
mergeParameters,
customParameters,
} from './utils/parameters.js';
type RouteObject = {
@ -242,8 +243,11 @@ export default function swaggerRoutes<T extends AnonymousRouter, R extends Route
components: {
schemas: translationSchemas,
parameters: identifiableEntityNames.reduce(
(previous, entityName) => ({ ...previous, ...buildPathIdParameters(entityName) }),
{}
(previous, entityName) => ({
...previous,
...buildPathIdParameters(entityName),
}),
customParameters()
),
},
tags: [...tags, ...additionalTags].map((tag) => ({ name: tag })),

View file

@ -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<string, OpenAPIV3.ParameterObject> => {
return Object.freeze({
tenantId: {
name: 'tenantId',
in: 'path',
description: 'The unique identifier of the tenant.',
required: true,
schema: {
type: 'string',
},
},
});
};