From 1e36284a27fe14b880204916a680a13f0d61712c Mon Sep 17 00:00:00 2001 From: osamu <46447427+sam-osamu@users.noreply.github.com> Date: Tue, 21 Nov 2023 11:43:58 +0900 Subject: [PATCH 1/8] =?UTF-8?q?api.json=E3=81=8Cswagger-cli=20validate?= =?UTF-8?q?=E3=81=A7=E3=82=A8=E3=83=A9=E3=83=BC=E3=81=AB=E3=81=AA=E3=82=89?= =?UTF-8?q?=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB=E7=94=9F=E6=88=90?= =?UTF-8?q?=E3=83=AD=E3=82=B8=E3=83=83=E3=82=AF=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/endpoints/federation/show-instance.ts | 9 ++--- .../src/server/api/openapi/gen-spec.ts | 38 ++++++++++++------- .../backend/src/server/api/openapi/schemas.ts | 13 ++++++- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/federation/show-instance.ts b/packages/backend/src/server/api/endpoints/federation/show-instance.ts index 71eec11235d6..781c15e742e6 100644 --- a/packages/backend/src/server/api/endpoints/federation/show-instance.ts +++ b/packages/backend/src/server/api/endpoints/federation/show-instance.ts @@ -16,12 +16,9 @@ export const meta = { requireCredential: false, res: { - oneOf: [{ - type: 'object', - ref: 'FederationInstance', - }, { - type: 'null', - }], + type: 'object', + optional: false, nullable: true, + ref: 'FederationInstance', }, } as const; diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts index 4f972d3f7e11..2f15a1846959 100644 --- a/packages/backend/src/server/api/openapi/gen-spec.ts +++ b/packages/backend/src/server/api/openapi/gen-spec.ts @@ -31,14 +31,6 @@ export function genOpenapiSpec(config: Config) { components: { schemas: schemas, - - securitySchemes: { - ApiKeyAuth: { - type: 'apiKey', - in: 'body', - name: 'i', - }, - }, }, }; @@ -67,6 +59,21 @@ export function genOpenapiSpec(config: Config) { const requestType = endpoint.meta.requireFile ? 'multipart/form-data' : 'application/json'; const schema = { ...endpoint.params }; + if (endpoint.meta.requireCredential) { + // https://swagger.io/docs/specification/authentication/api-keys/ + // ↑曰く、「can be "header", "query" or "cookie"」とのこと。 + // Misskeyはbodyに埋め込む形にしているので、各エンドポイントのパラメータに直接APIキー用のフィールドを追加する必要がある + schema.properties = { + 'i': { + type: 'string', + nullable: false, + description: 'API Key', + }, + ...schema.properties, + }; + schema.required = ['i', ...schema.required ?? []]; + } + if (endpoint.meta.requireFile) { schema.properties = { ...schema.properties, @@ -79,6 +86,11 @@ export function genOpenapiSpec(config: Config) { schema.required = [...schema.required ?? [], 'file']; } + if (schema.required && schema.required.length <= 0) { + // 空配列は許可されない + schema.required = undefined; + } + const info = { operationId: endpoint.name, summary: endpoint.name, @@ -90,11 +102,6 @@ export function genOpenapiSpec(config: Config) { ...(endpoint.meta.tags ? { tags: [endpoint.meta.tags[0]], } : {}), - ...(endpoint.meta.requireCredential ? { - security: [{ - ApiKeyAuth: [], - }], - } : {}), requestBody: { required: true, content: { @@ -118,6 +125,11 @@ export function genOpenapiSpec(config: Config) { description: 'OK (without any results)', }, }), + ...(endpoint.meta.res?.optional === true || endpoint.meta.res?.nullable === true ? { + '204': { + description: 'OK (without any results)', + }, + } : {}), '400': { description: 'Client error', content: { diff --git a/packages/backend/src/server/api/openapi/schemas.ts b/packages/backend/src/server/api/openapi/schemas.ts index 1a1d973e56d5..65efe4d31ce1 100644 --- a/packages/backend/src/server/api/openapi/schemas.ts +++ b/packages/backend/src/server/api/openapi/schemas.ts @@ -10,7 +10,11 @@ export function convertSchemaToOpenApiSchema(schema: Schema) { const res: any = schema; if (schema.type === 'object' && schema.properties) { - res.required = Object.entries(schema.properties).filter(([k, v]) => !v.optional).map(([k]) => k); + const required = Object.entries(schema.properties).filter(([k, v]) => !v.optional).map(([k]) => k); + if (required.length > 0) { + // 空配列は許可されない + res.required = required; + } for (const k of Object.keys(schema.properties)) { res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k]); @@ -32,8 +36,15 @@ export function convertSchemaToOpenApiSchema(schema: Schema) { } else { res.$ref = $ref; } + + // $refを抽出したので不要. + res.ref = undefined; } + // requiredを抽出したので不要. + // object以外の型も親階層のobjectによって列挙されているはずなので構わず消す + res.optional = undefined; + return res; } From c3773a3ad177a404db6cecb5e0590df12c02d322 Mon Sep 17 00:00:00 2001 From: osamu <46447427+sam-osamu@users.noreply.github.com> Date: Tue, 21 Nov 2023 21:25:07 +0900 Subject: [PATCH 2/8] =?UTF-8?q?=E3=83=95=E3=82=A3=E3=83=BC=E3=83=AB?= =?UTF-8?q?=E3=83=89=E3=81=AE=E6=B6=88=E3=81=97=E6=96=B9=E3=81=AB=E4=B8=8D?= =?UTF-8?q?=E5=82=99=E3=81=8C=E3=81=82=E3=81=A3=E3=81=9F=E3=81=AE=E3=81=A7?= =?UTF-8?q?=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/server/api/openapi/schemas.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/backend/src/server/api/openapi/schemas.ts b/packages/backend/src/server/api/openapi/schemas.ts index 65efe4d31ce1..2716f5f1629c 100644 --- a/packages/backend/src/server/api/openapi/schemas.ts +++ b/packages/backend/src/server/api/openapi/schemas.ts @@ -7,7 +7,9 @@ import type { Schema } from '@/misc/json-schema.js'; import { refs } from '@/misc/json-schema.js'; export function convertSchemaToOpenApiSchema(schema: Schema) { - const res: any = schema; + // optional, refはスキーマ定義に含まれないので分離しておく + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { optional, ref, ...res }: any = schema; if (schema.type === 'object' && schema.properties) { const required = Object.entries(schema.properties).filter(([k, v]) => !v.optional).map(([k]) => k); @@ -36,15 +38,8 @@ export function convertSchemaToOpenApiSchema(schema: Schema) { } else { res.$ref = $ref; } - - // $refを抽出したので不要. - res.ref = undefined; } - // requiredを抽出したので不要. - // object以外の型も親階層のobjectによって列挙されているはずなので構わず消す - res.optional = undefined; - return res; } From 61180ad9312068a9967137b159528da4f761b77a Mon Sep 17 00:00:00 2001 From: osamu <46447427+sam-osamu@users.noreply.github.com> Date: Tue, 21 Nov 2023 21:25:07 +0900 Subject: [PATCH 3/8] =?UTF-8?q?=E3=83=90=E3=83=83=E3=82=AF=E3=82=A8?= =?UTF-8?q?=E3=83=B3=E3=83=89=E3=82=92=E8=B5=B7=E5=8B=95=E3=81=97=E3=81=AA?= =?UTF-8?q?=E3=81=8F=E3=81=A6=E3=82=82api.json=E3=82=92=E4=BD=9C=E3=82=8C?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/generate_api_json.js | 8 ++++++++ packages/backend/package.json | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 packages/backend/generate_api_json.js diff --git a/packages/backend/generate_api_json.js b/packages/backend/generate_api_json.js new file mode 100644 index 000000000000..5819c60a5ff4 --- /dev/null +++ b/packages/backend/generate_api_json.js @@ -0,0 +1,8 @@ +import { loadConfig } from './built/config.js' +import { genOpenapiSpec } from './built/server/api/openapi/gen-spec.js' +import { writeFileSync } from "node:fs"; + +const config = loadConfig(); +const spec = genOpenapiSpec(config); + +writeFileSync('./built/api.json', JSON.stringify(spec), 'utf-8'); \ No newline at end of file diff --git a/packages/backend/package.json b/packages/backend/package.json index 3b029a49d2bc..18c7818dcc22 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -23,7 +23,8 @@ "jest-and-coverage": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit", "jest-clear": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --clearCache", "test": "pnpm jest", - "test-and-coverage": "pnpm jest-and-coverage" + "test-and-coverage": "pnpm jest-and-coverage", + "generate-api-json": "node ./generate_api_json.js" }, "optionalDependencies": { "@swc/core-android-arm64": "1.3.11", From 5cce089a82bbcfa9cad4f176e7b7be628f39f4f8 Mon Sep 17 00:00:00 2001 From: osamu <46447427+sam-osamu@users.noreply.github.com> Date: Wed, 22 Nov 2023 05:52:16 +0900 Subject: [PATCH 4/8] =?UTF-8?q?deepCopy=E3=81=97=E3=81=A6=E3=81=8B?= =?UTF-8?q?=E3=82=89=E3=83=AC=E3=82=B9=E3=83=9D=E3=83=B3=E3=82=B9=E9=83=A8?= =?UTF-8?q?=E5=88=86=E3=82=92=E4=BD=9C=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= =?UTF-8?q?=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/server/api/openapi/gen-spec.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts index 2f15a1846959..3546802440cd 100644 --- a/packages/backend/src/server/api/openapi/gen-spec.ts +++ b/packages/backend/src/server/api/openapi/gen-spec.ts @@ -4,7 +4,7 @@ */ import type { Config } from '@/config.js'; -import endpoints from '../endpoints.js'; +import endpoints, { IEndpoint } from '../endpoints.js'; import { errors as basicErrors } from './errors.js'; import { schemas, convertSchemaToOpenApiSchema } from './schemas.js'; @@ -34,7 +34,9 @@ export function genOpenapiSpec(config: Config) { }, }; - for (const endpoint of endpoints.filter(ep => !ep.meta.secure)) { + // 書き換えたりするのでディープコピーしておく。そのまま編集するとメモリ上の値が汚れて次回以降の出力に影響する + const copiedEndpoints = JSON.parse(JSON.stringify(endpoints)) as IEndpoint[]; + for (const endpoint of copiedEndpoints.filter(ep => !ep.meta.secure)) { const errors = {} as any; if (endpoint.meta.errors) { From 2fd053058d3680c8da78b9840d03fec46b815c65 Mon Sep 17 00:00:00 2001 From: osamu <46447427+sam-osamu@users.noreply.github.com> Date: Wed, 22 Nov 2023 08:10:30 +0900 Subject: [PATCH 5/8] fix CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7feb89b5462d..1113374595b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ ### Server - Fix: 時間経過により無効化されたアンテナを再有効化したとき、サーバ再起動までその状況が反映されないのを修正 #12303 - Fix: ロールタイムラインが保存されない問題を修正 +- Fix: api.jsonの生成ロジックを改善 #12402 ## 2023.11.1 From b043aaa97ca4293a1519fa81c2ae8f02cbae3b7d Mon Sep 17 00:00:00 2001 From: osamu <46447427+sam-osamu@users.noreply.github.com> Date: Wed, 22 Nov 2023 13:57:29 +0900 Subject: [PATCH 6/8] =?UTF-8?q?securitySchemes=E3=81=AE=E5=AE=9A=E7=BE=A9?= =?UTF-8?q?=E3=82=92=E5=BE=A9=E6=B4=BB=EF=BC=86ApiCallService=E3=81=AE?= =?UTF-8?q?=E5=AE=9F=E8=A3=85=E7=9A=84=E3=81=AB=E3=83=99=E3=82=A2=E3=83=A9?= =?UTF-8?q?=E3=83=88=E3=83=BC=E3=82=AF=E3=83=B3=E3=81=AA=E3=81=AE=E3=81=A7?= =?UTF-8?q?=E3=81=9D=E3=81=AE=E5=BD=A2=E3=81=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/server/api/openapi/gen-spec.ts | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts index 3546802440cd..ffad61b611ba 100644 --- a/packages/backend/src/server/api/openapi/gen-spec.ts +++ b/packages/backend/src/server/api/openapi/gen-spec.ts @@ -31,6 +31,13 @@ export function genOpenapiSpec(config: Config) { components: { schemas: schemas, + + securitySchemes: { + bearerAuth: { + type: 'http', + scheme: 'bearer', + }, + }, }, }; @@ -61,21 +68,6 @@ export function genOpenapiSpec(config: Config) { const requestType = endpoint.meta.requireFile ? 'multipart/form-data' : 'application/json'; const schema = { ...endpoint.params }; - if (endpoint.meta.requireCredential) { - // https://swagger.io/docs/specification/authentication/api-keys/ - // ↑曰く、「can be "header", "query" or "cookie"」とのこと。 - // Misskeyはbodyに埋め込む形にしているので、各エンドポイントのパラメータに直接APIキー用のフィールドを追加する必要がある - schema.properties = { - 'i': { - type: 'string', - nullable: false, - description: 'API Key', - }, - ...schema.properties, - }; - schema.required = ['i', ...schema.required ?? []]; - } - if (endpoint.meta.requireFile) { schema.properties = { ...schema.properties, @@ -104,6 +96,11 @@ export function genOpenapiSpec(config: Config) { ...(endpoint.meta.tags ? { tags: [endpoint.meta.tags[0]], } : {}), + ...(endpoint.meta.requireCredential ? { + security: [{ + bearerAuth: [], + }], + } : {}), requestBody: { required: true, content: { From 819f2a296c1f8d766e685aaffdd729ea27c7941c Mon Sep 17 00:00:00 2001 From: osamu <46447427+sam-osamu@users.noreply.github.com> Date: Wed, 22 Nov 2023 13:59:35 +0900 Subject: [PATCH 7/8] =?UTF-8?q?body=E3=81=8C=E7=84=A1=E3=81=84=EF=BC=88?= =?UTF-8?q?=E7=A9=BA=E3=82=AA=E3=83=96=E3=82=B8=E3=82=A7=E3=82=AF=E3=83=88?= =?UTF-8?q?=EF=BC=89=E3=81=AE=E3=81=A8=E3=81=8D=E3=81=AFrequestBody?= =?UTF-8?q?=E3=82=92=E6=8F=8F=E7=94=BB=E3=81=97=E3=81=AA=E3=81=84=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/src/server/api/openapi/gen-spec.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts index ffad61b611ba..9a00ecf37eb0 100644 --- a/packages/backend/src/server/api/openapi/gen-spec.ts +++ b/packages/backend/src/server/api/openapi/gen-spec.ts @@ -85,6 +85,8 @@ export function genOpenapiSpec(config: Config) { schema.required = undefined; } + const hasBody = (schema.type === 'object' && schema.properties && Object.keys(schema.properties).length >= 1); + const info = { operationId: endpoint.name, summary: endpoint.name, @@ -101,14 +103,16 @@ export function genOpenapiSpec(config: Config) { bearerAuth: [], }], } : {}), - requestBody: { - required: true, - content: { - [requestType]: { - schema, + ...(hasBody ? { + requestBody: { + required: true, + content: { + [requestType]: { + schema, + }, }, }, - }, + } : {}), responses: { ...(endpoint.meta.res ? { '200': { From a9cb82efd8d9622ec37f892ef89c7e1f48a322cd Mon Sep 17 00:00:00 2001 From: osamu <46447427+sam-osamu@users.noreply.github.com> Date: Wed, 22 Nov 2023 14:05:39 +0900 Subject: [PATCH 8/8] =?UTF-8?q?allowGet=E3=81=8Ctrue=E3=81=AA=E9=A0=85?= =?UTF-8?q?=E7=9B=AE=E3=81=AFget=E7=94=A8=E3=81=AE=E8=A8=98=E8=BC=89?= =?UTF-8?q?=E3=82=82=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/server/api/openapi/gen-spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts index 9a00ecf37eb0..30bf6b8b3e15 100644 --- a/packages/backend/src/server/api/openapi/gen-spec.ts +++ b/packages/backend/src/server/api/openapi/gen-spec.ts @@ -205,6 +205,7 @@ export function genOpenapiSpec(config: Config) { }; spec.paths['/' + endpoint.name] = { + ...(endpoint.meta.allowGet ? { get: info } : {}), post: info, }; }