194 lines
4.1 KiB
TypeScript
194 lines
4.1 KiB
TypeScript
|
import type { Config } from '@/config.js';
|
||
|
import endpoints from '../endpoints.js';
|
||
|
import { errors as basicErrors } from './errors.js';
|
||
|
import { schemas, convertSchemaToOpenApiSchema } from './schemas.js';
|
||
|
|
||
|
export function genOpenapiSpec(config: Config) {
|
||
|
const spec = {
|
||
|
openapi: '3.0.0',
|
||
|
|
||
|
info: {
|
||
|
version: config.version,
|
||
|
title: 'Misskey API',
|
||
|
'x-logo': { url: '/static-assets/api-doc.png' },
|
||
|
},
|
||
|
|
||
|
externalDocs: {
|
||
|
description: 'Repository',
|
||
|
url: 'https://github.com/misskey-dev/misskey',
|
||
|
},
|
||
|
|
||
|
servers: [{
|
||
|
url: config.apiUrl,
|
||
|
}],
|
||
|
|
||
|
paths: {} as any,
|
||
|
|
||
|
components: {
|
||
|
schemas: schemas,
|
||
|
|
||
|
securitySchemes: {
|
||
|
ApiKeyAuth: {
|
||
|
type: 'apiKey',
|
||
|
in: 'body',
|
||
|
name: 'i',
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
|
||
|
for (const endpoint of endpoints.filter(ep => !ep.meta.secure)) {
|
||
|
const errors = {} as any;
|
||
|
|
||
|
if (endpoint.meta.errors) {
|
||
|
for (const e of Object.values(endpoint.meta.errors)) {
|
||
|
errors[e.code] = {
|
||
|
value: {
|
||
|
error: e,
|
||
|
},
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const resSchema = endpoint.meta.res ? convertSchemaToOpenApiSchema(endpoint.meta.res) : {};
|
||
|
|
||
|
let desc = (endpoint.meta.description ? endpoint.meta.description : 'No description provided.') + '\n\n';
|
||
|
desc += `**Credential required**: *${endpoint.meta.requireCredential ? 'Yes' : 'No'}*`;
|
||
|
if (endpoint.meta.kind) {
|
||
|
const kind = endpoint.meta.kind;
|
||
|
desc += ` / **Permission**: *${kind}*`;
|
||
|
}
|
||
|
|
||
|
const requestType = endpoint.meta.requireFile ? 'multipart/form-data' : 'application/json';
|
||
|
const schema = { ...endpoint.params };
|
||
|
|
||
|
if (endpoint.meta.requireFile) {
|
||
|
schema.properties = {
|
||
|
...schema.properties,
|
||
|
file: {
|
||
|
type: 'string',
|
||
|
format: 'binary',
|
||
|
description: 'The file contents.',
|
||
|
},
|
||
|
};
|
||
|
schema.required = [...schema.required ?? [], 'file'];
|
||
|
}
|
||
|
|
||
|
const info = {
|
||
|
operationId: endpoint.name,
|
||
|
summary: endpoint.name,
|
||
|
description: desc,
|
||
|
externalDocs: {
|
||
|
description: 'Source code',
|
||
|
url: `https://github.com/misskey-dev/misskey/blob/develop/packages/backend/src/server/api/endpoints/${endpoint.name}.ts`,
|
||
|
},
|
||
|
...(endpoint.meta.tags ? {
|
||
|
tags: [endpoint.meta.tags[0]],
|
||
|
} : {}),
|
||
|
...(endpoint.meta.requireCredential ? {
|
||
|
security: [{
|
||
|
ApiKeyAuth: [],
|
||
|
}],
|
||
|
} : {}),
|
||
|
requestBody: {
|
||
|
required: true,
|
||
|
content: {
|
||
|
[requestType]: {
|
||
|
schema,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
responses: {
|
||
|
...(endpoint.meta.res ? {
|
||
|
'200': {
|
||
|
description: 'OK (with results)',
|
||
|
content: {
|
||
|
'application/json': {
|
||
|
schema: resSchema,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
} : {
|
||
|
'204': {
|
||
|
description: 'OK (without any results)',
|
||
|
},
|
||
|
}),
|
||
|
'400': {
|
||
|
description: 'Client error',
|
||
|
content: {
|
||
|
'application/json': {
|
||
|
schema: {
|
||
|
$ref: '#/components/schemas/Error',
|
||
|
},
|
||
|
examples: { ...errors, ...basicErrors['400'] },
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
'401': {
|
||
|
description: 'Authentication error',
|
||
|
content: {
|
||
|
'application/json': {
|
||
|
schema: {
|
||
|
$ref: '#/components/schemas/Error',
|
||
|
},
|
||
|
examples: basicErrors['401'],
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
'403': {
|
||
|
description: 'Forbidden error',
|
||
|
content: {
|
||
|
'application/json': {
|
||
|
schema: {
|
||
|
$ref: '#/components/schemas/Error',
|
||
|
},
|
||
|
examples: basicErrors['403'],
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
'418': {
|
||
|
description: 'I\'m Ai',
|
||
|
content: {
|
||
|
'application/json': {
|
||
|
schema: {
|
||
|
$ref: '#/components/schemas/Error',
|
||
|
},
|
||
|
examples: basicErrors['418'],
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
...(endpoint.meta.limit ? {
|
||
|
'429': {
|
||
|
description: 'To many requests',
|
||
|
content: {
|
||
|
'application/json': {
|
||
|
schema: {
|
||
|
$ref: '#/components/schemas/Error',
|
||
|
},
|
||
|
examples: basicErrors['429'],
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
} : {}),
|
||
|
'500': {
|
||
|
description: 'Internal server error',
|
||
|
content: {
|
||
|
'application/json': {
|
||
|
schema: {
|
||
|
$ref: '#/components/schemas/Error',
|
||
|
},
|
||
|
examples: basicErrors['500'],
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
|
||
|
spec.paths['/' + endpoint.name] = {
|
||
|
post: info,
|
||
|
};
|
||
|
}
|
||
|
|
||
|
return spec;
|
||
|
}
|