Introduce OpenAPI specs (#4351)

* wip

* wip

* wip

* Update index.ts

* Update gen-openapi-spec.ts

* Update api.ja-JP.md

* Fix

* Improve doc

* Update gen-openapi-spec.ts

* Update redoc.html

* Improve doc

* Update gen-openapi-spec.ts

* Improve doc

* Update CHANGELOG.md
This commit is contained in:
syuilo
2019-02-23 11:20:58 +09:00
committed by GitHub
parent 68a6758302
commit 52774bbe64
173 changed files with 1091 additions and 876 deletions

View File

@@ -10,11 +10,9 @@ import ms = require('ms');
import * as Router from 'koa-router';
import * as send from 'koa-send';
import * as glob from 'glob';
import * as yaml from 'js-yaml';
import config from '../../config';
import { licenseHtml } from '../../misc/license';
import { copyright } from '../../const.json';
import endpoints from '../api/endpoints';
import * as locales from '../../../locales';
import * as nestedProperty from 'nested-property';
@@ -33,14 +31,6 @@ async function genVars(lang: string): Promise<{ [key: string]: any }> {
const cwd = path.resolve(__dirname + '/../../../') + '/';
vars['endpoints'] = endpoints;
const entities = glob.sync('src/docs/api/entities/**/*.yaml', { cwd });
vars['entities'] = entities.map(x => {
const _x = yaml.safeLoad(fs.readFileSync(cwd + x, 'utf-8'));
return _x.name;
});
const docs = glob.sync(`src/docs/**/*.${lang}.md`, { cwd });
vars['docs'] = {};
for (const x of docs) {
@@ -67,82 +57,6 @@ async function genVars(lang: string): Promise<{ [key: string]: any }> {
return vars;
}
// WIP type
const parseParamDefinition = (key: string, x: any) => {
return Object.assign({
name: key,
type: x.validator.getType()
}, x);
};
const parsePropDefinition = (key: string, prop: any) => {
const id = prop.type.match(/^id\((.+?)\)|^id/);
const entity = prop.type.match(/^entity\((.+?)\)/);
const isObject = /^object/.test(prop.type);
const isDate = /^date/.test(prop.type);
const isArray = /\[\]$/.test(prop.type);
if (id) {
prop.kind = 'id';
prop.type = 'string';
prop.entity = id[1];
if (isArray) {
prop.type += '[]';
}
}
if (entity) {
prop.kind = 'entity';
prop.type = 'object';
prop.entity = entity[1];
if (isArray) {
prop.type += '[]';
}
}
if (isObject) {
prop.kind = 'object';
if (prop.props) {
prop.hasDef = true;
}
}
if (isDate) {
prop.kind = 'date';
prop.type = 'string';
if (isArray) {
prop.type += '[]';
}
}
if (prop.optional) {
prop.type += '?';
}
prop.name = key;
return prop;
};
const sortParams = (params: { name: string }[]) => {
return params;
};
const extractPropDefRef = (props: any[]) => {
let defs: any[] = [];
for (const [k, v] of Object.entries(props)) {
if (v.props) {
defs.push({
name: k,
props: sortParams(Object.entries(v.props).map(([k, v]) => parsePropDefinition(k, v)))
});
const childDefs = extractPropDefRef(v.props);
defs = defs.concat(childDefs);
}
}
return sortParams(defs);
};
const router = new Router();
router.get('/assets/*', async ctx => {
@@ -152,49 +66,6 @@ router.get('/assets/*', async ctx => {
});
});
router.get('/*/api/endpoints/*', async ctx => {
const lang = getLang(ctx.params[0]);
const name = ctx.params[1];
const ep = endpoints.find(e => e.name === name);
const vars = {
id: `api/endpoints/${name}`,
title: name,
endpoint: ep.meta,
endpointUrl: {
host: config.api_url,
path: name
},
// @ts-ignore
params: ep.meta.params ? sortParams(Object.entries(ep.meta.params).map(([k, v]) => parseParamDefinition(k, v))) : null,
res: ep.meta.res,
resProps: ep.meta.res && ep.meta.res.props ? sortParams(Object.entries(ep.meta.res.props).map(([k, v]) => parsePropDefinition(k, v))) : null,
resDefs: null as any, //extractPropDefRef(Object.entries(ep.res.props).map(([k, v]) => parsePropDefinition(k, v)))
src: `https://github.com/syuilo/misskey/tree/master/src/server/api/endpoints/${name}.ts`
};
await ctx.render('../../../../src/docs/api/endpoints/view', Object.assign(await genVars(lang), vars));
ctx.set('Cache-Control', 'public, max-age=300');
});
router.get('/*/api/entities/*', async ctx => {
const lang = getLang(ctx.params[0]);
const entity = ctx.params[1];
const x = yaml.safeLoad(fs.readFileSync(path.resolve(`${__dirname}/../../../src/docs/api/entities/${entity}.yaml`), 'utf-8'));
await ctx.render('../../../../src/docs/api/entities/view', Object.assign(await genVars(lang), {
id: `api/entities/${entity}`,
name: x.name,
desc: x.desc,
props: sortParams(Object.entries(x.props).map(([k, v]) => parsePropDefinition(k, v))),
propDefs: extractPropDefRef(x.props)
}));
ctx.set('Cache-Control', 'public, max-age=300');
});
router.get('/*/*', async ctx => {
const lang = getLang(ctx.params[0]);
const doc = ctx.params[1];