From 54fc232a23742ca62232d35c8e976cbec40a61d2 Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Sat, 8 Feb 2025 17:29:24 +0900 Subject: [PATCH] fix(backend): use unique `operationId` in the OpenAPI schema (#15420) * fix(backend): use unique `operationId` in the OpenAPI schema * fix: read with UTF-8 encoding --- .../src/server/api/openapi/gen-spec.ts | 10 ++++-- .../misskey-js/generator/src/generator.ts | 33 ++++++++++++++++--- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts index 3b20ec1321..ea64e32ee6 100644 --- a/packages/backend/src/server/api/openapi/gen-spec.ts +++ b/packages/backend/src/server/api/openapi/gen-spec.ts @@ -210,9 +210,15 @@ export function genOpenapiSpec(config: Config, includeSelfRef = false) { spec.paths['/' + endpoint.name] = { ...(endpoint.meta.allowGet ? { - get: info, + get: { + ...info, + operationId: 'get___' + info.operationId, + }, } : {}), - post: info, + post: { + ...info, + operationId: 'post___' + info.operationId, + }, }; } diff --git a/packages/misskey-js/generator/src/generator.ts b/packages/misskey-js/generator/src/generator.ts index 88f2ae9ee9..a77ffeedc2 100644 --- a/packages/misskey-js/generator/src/generator.ts +++ b/packages/misskey-js/generator/src/generator.ts @@ -1,8 +1,9 @@ -import { mkdir, writeFile } from 'fs/promises'; +import assert from 'assert'; +import { mkdir, readFile, writeFile } from 'fs/promises'; import { OpenAPIV3_1 } from 'openapi-types'; import { toPascal } from 'ts-case-convert'; import OpenAPIParser from '@readme/openapi-parser'; -import openapiTS from 'openapi-typescript'; +import openapiTS, { OpenAPI3, OperationObject, PathItemObject } from 'openapi-typescript'; async function generateBaseTypes( openApiDocs: OpenAPIV3_1.Document, @@ -20,7 +21,29 @@ async function generateBaseTypes( } lines.push(''); - const generatedTypes = await openapiTS(openApiJsonPath, { + // NOTE: Align `operationId` of GET and POST to avoid duplication of type definitions + const openApi = JSON.parse(await readFile(openApiJsonPath, 'utf8')) as OpenAPI3; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + for (const [key, item] of Object.entries(openApi.paths!)) { + assert('post' in item); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + openApi.paths![key] = { + ...('get' in item ? { + get: { + ...item.get, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + operationId: ((item as PathItemObject).get as OperationObject).operationId!.replaceAll('get___', ''), + }, + } : {}), + post: { + ...item.post, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + operationId: ((item as PathItemObject).post as OperationObject).operationId!.replaceAll('post___', ''), + }, + }; + } + + const generatedTypes = await openapiTS(openApi, { exportType: true, transform(schemaObject) { if ('format' in schemaObject && schemaObject.format === 'binary') { @@ -78,7 +101,7 @@ async function generateEndpoints( for (const operation of postPathItems) { const path = operation._path_; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const operationId = operation.operationId!; + const operationId = operation.operationId!.replaceAll('get___', '').replaceAll('post___', ''); const endpoint = new Endpoint(path); endpoints.push(endpoint); @@ -195,7 +218,7 @@ async function generateApiClientJSDoc( for (const operation of postPathItems) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const operationId = operation.operationId!; + const operationId = operation.operationId!.replaceAll('get___', '').replaceAll('post___', ''); if (operation.description) { endpoints.push({