swagger-cli validateがvalidとなるapi.jsonを作れるようにする (#12403)
* api.jsonがswagger-cli validateでエラーにならないように生成ロジックを修正 * フィールドの消し方に不備があったので変更 * バックエンドを起動しなくてもapi.jsonを作れるようにした * deepCopyしてからレスポンス部分を作るようにした * fix CHANGELOG.md * securitySchemesの定義を復活&ApiCallServiceの実装的にベアラトークンなのでその形で * bodyが無い(空オブジェクト)のときはrequestBodyを描画しないようにする * allowGetがtrueな項目はget用の記載も作成 --------- Co-authored-by: osamu <46447427+sam-osamu@users.noreply.github.com> Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
This commit is contained in:
		| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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'; | ||||
|  | ||||
| @@ -33,16 +33,17 @@ export function genOpenapiSpec(config: Config) { | ||||
| 			schemas: schemas, | ||||
|  | ||||
| 			securitySchemes: { | ||||
| 				ApiKeyAuth: { | ||||
| 					type: 'apiKey', | ||||
| 					in: 'body', | ||||
| 					name: 'i', | ||||
| 				bearerAuth: { | ||||
| 					type: 'http', | ||||
| 					scheme: 'bearer', | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	}; | ||||
|  | ||||
| 	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) { | ||||
| @@ -79,6 +80,13 @@ export function genOpenapiSpec(config: Config) { | ||||
| 			schema.required = [...schema.required ?? [], 'file']; | ||||
| 		} | ||||
|  | ||||
| 		if (schema.required && schema.required.length <= 0) { | ||||
| 			// 空配列は許可されない | ||||
| 			schema.required = undefined; | ||||
| 		} | ||||
|  | ||||
| 		const hasBody = (schema.type === 'object' && schema.properties && Object.keys(schema.properties).length >= 1); | ||||
|  | ||||
| 		const info = { | ||||
| 			operationId: endpoint.name, | ||||
| 			summary: endpoint.name, | ||||
| @@ -92,17 +100,19 @@ export function genOpenapiSpec(config: Config) { | ||||
| 			} : {}), | ||||
| 			...(endpoint.meta.requireCredential ? { | ||||
| 				security: [{ | ||||
| 					ApiKeyAuth: [], | ||||
| 					bearerAuth: [], | ||||
| 				}], | ||||
| 			} : {}), | ||||
| 			requestBody: { | ||||
| 				required: true, | ||||
| 				content: { | ||||
| 					[requestType]: { | ||||
| 						schema, | ||||
| 			...(hasBody ? { | ||||
| 				requestBody: { | ||||
| 					required: true, | ||||
| 					content: { | ||||
| 						[requestType]: { | ||||
| 							schema, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			} : {}), | ||||
| 			responses: { | ||||
| 				...(endpoint.meta.res ? { | ||||
| 					'200': { | ||||
| @@ -118,6 +128,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: { | ||||
| @@ -190,6 +205,7 @@ export function genOpenapiSpec(config: Config) { | ||||
| 		}; | ||||
|  | ||||
| 		spec.paths['/' + endpoint.name] = { | ||||
| 			...(endpoint.meta.allowGet ? { get: info } : {}), | ||||
| 			post: info, | ||||
| 		}; | ||||
| 	} | ||||
|   | ||||
| @@ -7,10 +7,16 @@ 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) { | ||||
| 		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]); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 おさむのひと
					おさむのひと