fix: api-docが開けない問題を修正 (#13132)
* refactor: 自己参照を使用している箇所に`selfRef`を持たせるように * feat: スキーマ生成時に自己参照を含むかどうかを指定できるように * fix: api.jsonにselfRefが含まれているのを修正 * refactor: 他の箇所と同様にselfRefの除去を行うように * remove: 不要なimportを削除
This commit is contained in:
		
							parent
							
								
									3499814498
								
							
						
					
					
						commit
						d8bdbd53ed
					
				
					 5 changed files with 43 additions and 39 deletions
				
			
		| 
						 | 
				
			
			@ -3,6 +3,6 @@ import { genOpenapiSpec } from './built/server/api/openapi/gen-spec.js'
 | 
			
		|||
import { writeFileSync } from "node:fs";
 | 
			
		||||
 | 
			
		||||
const config = loadConfig();
 | 
			
		||||
const spec = genOpenapiSpec(config);
 | 
			
		||||
const spec = genOpenapiSpec(config, true);
 | 
			
		||||
 | 
			
		||||
writeFileSync('./built/api.json', JSON.stringify(spec), 'utf-8');
 | 
			
		||||
| 
						 | 
				
			
			@ -119,6 +119,7 @@ export interface Schema extends OfSchema {
 | 
			
		|||
	readonly example?: any;
 | 
			
		||||
	readonly format?: string;
 | 
			
		||||
	readonly ref?: keyof typeof refs;
 | 
			
		||||
	readonly selfRef?: boolean;
 | 
			
		||||
	readonly enum?: ReadonlyArray<string | null>;
 | 
			
		||||
	readonly default?: (this['type'] extends TypeStringef ? StringDefToType<this['type']> : any) | null;
 | 
			
		||||
	readonly maxLength?: number;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,6 +53,7 @@ const sectionBlockSchema = {
 | 
			
		|||
				type: 'object',
 | 
			
		||||
				optional: false, nullable: false,
 | 
			
		||||
				ref: 'PageBlock',
 | 
			
		||||
				selfRef: true,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,9 +6,9 @@
 | 
			
		|||
import type { Config } from '@/config.js';
 | 
			
		||||
import endpoints, { IEndpoint } from '../endpoints.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 = {
 | 
			
		||||
		openapi: '3.1.0',
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ export function genOpenapiSpec(config: Config) {
 | 
			
		|||
		paths: {} as any,
 | 
			
		||||
 | 
			
		||||
		components: {
 | 
			
		||||
			schemas: schemas,
 | 
			
		||||
			schemas: getSchemas(includeSelfRef),
 | 
			
		||||
 | 
			
		||||
			securitySchemes: {
 | 
			
		||||
				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';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +71,7 @@ export function genOpenapiSpec(config: Config) {
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		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) {
 | 
			
		||||
			schema.properties = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,10 +6,10 @@
 | 
			
		|||
import type { Schema } 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はスキーマ定義に含まれないので分離しておく
 | 
			
		||||
	// 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 (type === 'res') {
 | 
			
		||||
| 
						 | 
				
			
			@ -21,20 +21,20 @@ export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 're
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		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) {
 | 
			
		||||
		res.items = convertSchemaToOpenApiSchema(schema.items, type);
 | 
			
		||||
		res.items = convertSchemaToOpenApiSchema(schema.items, type, includeSelfRef);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (const o of ['anyOf', 'oneOf', 'allOf'] as const) {
 | 
			
		||||
		// 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}`;
 | 
			
		||||
		if (schema.nullable || schema.optional) {
 | 
			
		||||
			res.allOf = [{ $ref }];
 | 
			
		||||
| 
						 | 
				
			
			@ -54,35 +54,37 @@ export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 're
 | 
			
		|||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const schemas = {
 | 
			
		||||
	Error: {
 | 
			
		||||
		type: 'object',
 | 
			
		||||
		properties: {
 | 
			
		||||
			error: {
 | 
			
		||||
				type: 'object',
 | 
			
		||||
				description: 'An error object.',
 | 
			
		||||
				properties: {
 | 
			
		||||
					code: {
 | 
			
		||||
						type: 'string',
 | 
			
		||||
						description: 'An error code. Unique within the endpoint.',
 | 
			
		||||
					},
 | 
			
		||||
					message: {
 | 
			
		||||
						type: 'string',
 | 
			
		||||
						description: 'An error message.',
 | 
			
		||||
					},
 | 
			
		||||
					id: {
 | 
			
		||||
						type: 'string',
 | 
			
		||||
						format: 'uuid',
 | 
			
		||||
						description: 'An error ID. This ID is static.',
 | 
			
		||||
export function getSchemas(includeSelfRef: boolean) {
 | 
			
		||||
	return {
 | 
			
		||||
		Error: {
 | 
			
		||||
			type: 'object',
 | 
			
		||||
			properties: {
 | 
			
		||||
				error: {
 | 
			
		||||
					type: 'object',
 | 
			
		||||
					description: 'An error object.',
 | 
			
		||||
					properties: {
 | 
			
		||||
						code: {
 | 
			
		||||
							type: 'string',
 | 
			
		||||
							description: 'An error code. Unique within the endpoint.',
 | 
			
		||||
						},
 | 
			
		||||
						message: {
 | 
			
		||||
							type: 'string',
 | 
			
		||||
							description: 'An error message.',
 | 
			
		||||
						},
 | 
			
		||||
						id: {
 | 
			
		||||
							type: 'string',
 | 
			
		||||
							format: 'uuid',
 | 
			
		||||
							description: 'An error ID. This ID is static.',
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
					required: ['code', 'id', 'message'],
 | 
			
		||||
				},
 | 
			
		||||
				required: ['code', 'id', 'message'],
 | 
			
		||||
			},
 | 
			
		||||
			required: ['error'],
 | 
			
		||||
		},
 | 
			
		||||
		required: ['error'],
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	...Object.fromEntries(
 | 
			
		||||
		Object.entries(refs).map(([key, schema]) => [key, convertSchemaToOpenApiSchema(schema, 'res')]),
 | 
			
		||||
	),
 | 
			
		||||
};
 | 
			
		||||
		...Object.fromEntries(
 | 
			
		||||
			Object.entries(refs).map(([key, schema]) => [key, convertSchemaToOpenApiSchema(schema, 'res', includeSelfRef)]),
 | 
			
		||||
		),
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue