Compare commits
6 commits
main
...
feature/ap
Author | SHA1 | Date | |
---|---|---|---|
f3b1c1d7ae | |||
fb795607ef | |||
4c055456d2 | |||
aefe15e8ed | |||
fad8dad5d8 | |||
ca6156fe71 |
5 changed files with 56 additions and 5 deletions
|
@ -5,12 +5,23 @@ import authenticate, { AuthenticationError } from './authenticate.js';
|
|||
import call from './call.js';
|
||||
import { ApiError } from './error.js';
|
||||
|
||||
function getRequestArguments(ctx: Koa.Context): any {
|
||||
const args = {
|
||||
...(ctx.params || {}),
|
||||
...ctx.query,
|
||||
...(ctx.request.body || {}),
|
||||
};
|
||||
|
||||
// For security reasons, we drop the i parameter if it's a GET request
|
||||
if (ctx.method === 'GET') {
|
||||
delete args['i'];
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export async function handler(endpoint: IEndpoint, ctx: Koa.Context): Promise<void> {
|
||||
const body = ctx.is('multipart/form-data')
|
||||
? (ctx.request as any).body
|
||||
: ctx.method === 'GET'
|
||||
? ctx.query
|
||||
: ctx.request.body;
|
||||
const body = getRequestArguments(ctx);
|
||||
|
||||
const error = (e: ApiError): void => {
|
||||
ctx.status = e.httpStatusCode;
|
||||
|
|
|
@ -702,6 +702,24 @@ export interface IEndpointMeta {
|
|||
* 正常応答をキャッシュ (Cache-Control: public) する秒数
|
||||
*/
|
||||
readonly cacheSec?: number;
|
||||
|
||||
/**
|
||||
* API v2 options
|
||||
*/
|
||||
readonly v2?: {
|
||||
|
||||
/**
|
||||
* HTTP verb this endpoint supports
|
||||
*/
|
||||
readonly method: string;
|
||||
|
||||
/**
|
||||
* Path alias for v2 endpoint
|
||||
*
|
||||
* @example (v0) /api/notes/create -> /api/v2/notes
|
||||
*/
|
||||
readonly alias?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IEndpoint {
|
||||
|
|
|
@ -10,6 +10,10 @@ export const meta = {
|
|||
|
||||
requireCredential: false,
|
||||
|
||||
v2: {
|
||||
method: 'get',
|
||||
},
|
||||
|
||||
allowGet: true,
|
||||
cacheSec: 60,
|
||||
|
||||
|
|
|
@ -69,6 +69,11 @@ for (const endpoint of endpoints) {
|
|||
} else {
|
||||
router.get(`/${endpoint.name}`, async ctx => { ctx.status = 405; });
|
||||
}
|
||||
|
||||
if (endpoint.meta.v2) {
|
||||
const path = endpoint.meta.v2.alias ?? endpoint.name.replace(/-/g, '_');
|
||||
router[endpoint.meta.v2.method](`/v2/${path}`, handler.bind(null, endpoint));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -207,6 +207,19 @@ export function genOpenapiSpec() {
|
|||
}
|
||||
|
||||
spec.paths['/' + endpoint.name] = path;
|
||||
|
||||
if (endpoint.meta.v2) {
|
||||
// we need a clone of the API endpoint info because otherwise we change it by reference
|
||||
const infoClone = JSON.parse(JSON.stringify(info));
|
||||
const route = `/v2/${endpoint.meta.v2.alias ?? endpoint.name.replace(/-/g, '_')}`;
|
||||
|
||||
infoClone['operationId'] = infoClone['summary'] = route;
|
||||
|
||||
spec.paths[route] = {
|
||||
...spec.paths[route],
|
||||
[endpoint.meta.v2.method]: infoClone,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return spec;
|
||||
|
|
Loading…
Reference in a new issue