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] =?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 71eec11235..781c15e742 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 4f972d3f7e..2f15a18469 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 1a1d973e56..65efe4d31c 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; }