fix: api-docが開けない問題を修正 (#13132)
* refactor: 自己参照を使用している箇所に`selfRef`を持たせるように * feat: スキーマ生成時に自己参照を含むかどうかを指定できるように * fix: api.jsonにselfRefが含まれているのを修正 * refactor: 他の箇所と同様にselfRefの除去を行うように * remove: 不要なimportを削除
This commit is contained in:
parent
3499814498
commit
d8bdbd53ed
|
@ -3,6 +3,6 @@ import { genOpenapiSpec } from './built/server/api/openapi/gen-spec.js'
|
||||||
import { writeFileSync } from "node:fs";
|
import { writeFileSync } from "node:fs";
|
||||||
|
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
const spec = genOpenapiSpec(config);
|
const spec = genOpenapiSpec(config, true);
|
||||||
|
|
||||||
writeFileSync('./built/api.json', JSON.stringify(spec), 'utf-8');
|
writeFileSync('./built/api.json', JSON.stringify(spec), 'utf-8');
|
|
@ -119,6 +119,7 @@ export interface Schema extends OfSchema {
|
||||||
readonly example?: any;
|
readonly example?: any;
|
||||||
readonly format?: string;
|
readonly format?: string;
|
||||||
readonly ref?: keyof typeof refs;
|
readonly ref?: keyof typeof refs;
|
||||||
|
readonly selfRef?: boolean;
|
||||||
readonly enum?: ReadonlyArray<string | null>;
|
readonly enum?: ReadonlyArray<string | null>;
|
||||||
readonly default?: (this['type'] extends TypeStringef ? StringDefToType<this['type']> : any) | null;
|
readonly default?: (this['type'] extends TypeStringef ? StringDefToType<this['type']> : any) | null;
|
||||||
readonly maxLength?: number;
|
readonly maxLength?: number;
|
||||||
|
|
|
@ -53,6 +53,7 @@ const sectionBlockSchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
ref: 'PageBlock',
|
ref: 'PageBlock',
|
||||||
|
selfRef: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import endpoints, { IEndpoint } from '../endpoints.js';
|
import endpoints, { IEndpoint } from '../endpoints.js';
|
||||||
import { errors as basicErrors } from './errors.js';
|
import { errors as basicErrors } from './errors.js';
|
||||||
import { schemas, convertSchemaToOpenApiSchema } from './schemas.js';
|
import { getSchemas, convertSchemaToOpenApiSchema } from './schemas.js';
|
||||||
|
|
||||||
export function genOpenapiSpec(config: Config) {
|
export function genOpenapiSpec(config: Config, includeSelfRef = false) {
|
||||||
const spec = {
|
const spec = {
|
||||||
openapi: '3.1.0',
|
openapi: '3.1.0',
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ export function genOpenapiSpec(config: Config) {
|
||||||
paths: {} as any,
|
paths: {} as any,
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
schemas: schemas,
|
schemas: getSchemas(includeSelfRef),
|
||||||
|
|
||||||
securitySchemes: {
|
securitySchemes: {
|
||||||
bearerAuth: {
|
bearerAuth: {
|
||||||
|
@ -56,7 +56,7 @@ export function genOpenapiSpec(config: Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const resSchema = endpoint.meta.res ? convertSchemaToOpenApiSchema(endpoint.meta.res, 'res') : {};
|
const resSchema = endpoint.meta.res ? convertSchemaToOpenApiSchema(endpoint.meta.res, 'res', includeSelfRef) : {};
|
||||||
|
|
||||||
let desc = (endpoint.meta.description ? endpoint.meta.description : 'No description provided.') + '\n\n';
|
let desc = (endpoint.meta.description ? endpoint.meta.description : 'No description provided.') + '\n\n';
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ export function genOpenapiSpec(config: Config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const requestType = endpoint.meta.requireFile ? 'multipart/form-data' : 'application/json';
|
const requestType = endpoint.meta.requireFile ? 'multipart/form-data' : 'application/json';
|
||||||
const schema = { ...convertSchemaToOpenApiSchema(endpoint.params, 'param') };
|
const schema = { ...convertSchemaToOpenApiSchema(endpoint.params, 'param', false) };
|
||||||
|
|
||||||
if (endpoint.meta.requireFile) {
|
if (endpoint.meta.requireFile) {
|
||||||
schema.properties = {
|
schema.properties = {
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
import type { Schema } from '@/misc/json-schema.js';
|
import type { Schema } from '@/misc/json-schema.js';
|
||||||
import { refs } from '@/misc/json-schema.js';
|
import { refs } from '@/misc/json-schema.js';
|
||||||
|
|
||||||
export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 'res') {
|
export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 'res', includeSelfRef: boolean): any {
|
||||||
// optional, nullable, refはスキーマ定義に含まれないので分離しておく
|
// optional, nullable, refはスキーマ定義に含まれないので分離しておく
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const { optional, nullable, ref, ...res }: any = schema;
|
const { optional, nullable, ref, selfRef, ...res }: any = schema;
|
||||||
|
|
||||||
if (schema.type === 'object' && schema.properties) {
|
if (schema.type === 'object' && schema.properties) {
|
||||||
if (type === 'res') {
|
if (type === 'res') {
|
||||||
|
@ -21,20 +21,20 @@ export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 're
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const k of Object.keys(schema.properties)) {
|
for (const k of Object.keys(schema.properties)) {
|
||||||
res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k], type);
|
res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k], type, includeSelfRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema.type === 'array' && schema.items) {
|
if (schema.type === 'array' && schema.items) {
|
||||||
res.items = convertSchemaToOpenApiSchema(schema.items, type);
|
res.items = convertSchemaToOpenApiSchema(schema.items, type, includeSelfRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const o of ['anyOf', 'oneOf', 'allOf'] as const) {
|
for (const o of ['anyOf', 'oneOf', 'allOf'] as const) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
if (o in schema) res[o] = schema[o]!.map(schema => convertSchemaToOpenApiSchema(schema, type));
|
if (o in schema) res[o] = schema[o]!.map(schema => convertSchemaToOpenApiSchema(schema, type, includeSelfRef));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'res' && schema.ref) {
|
if (type === 'res' && schema.ref && (!schema.selfRef || includeSelfRef)) {
|
||||||
const $ref = `#/components/schemas/${schema.ref}`;
|
const $ref = `#/components/schemas/${schema.ref}`;
|
||||||
if (schema.nullable || schema.optional) {
|
if (schema.nullable || schema.optional) {
|
||||||
res.allOf = [{ $ref }];
|
res.allOf = [{ $ref }];
|
||||||
|
@ -54,7 +54,8 @@ export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 're
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const schemas = {
|
export function getSchemas(includeSelfRef: boolean) {
|
||||||
|
return {
|
||||||
Error: {
|
Error: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -83,6 +84,7 @@ export const schemas = {
|
||||||
},
|
},
|
||||||
|
|
||||||
...Object.fromEntries(
|
...Object.fromEntries(
|
||||||
Object.entries(refs).map(([key, schema]) => [key, convertSchemaToOpenApiSchema(schema, 'res')]),
|
Object.entries(refs).map(([key, schema]) => [key, convertSchemaToOpenApiSchema(schema, 'res', includeSelfRef)]),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue