forked from FoundKeyGang/FoundKey
server: refactor API handler and returning errors
This refactors the API handler to not use default exports, be async instead of constructing a promise and modify how errors are returned.
This commit is contained in:
parent
c3c7164dfb
commit
66d7b69377
2 changed files with 30 additions and 33 deletions
|
@ -5,59 +5,56 @@ import authenticate, { AuthenticationError } from './authenticate.js';
|
||||||
import call from './call.js';
|
import call from './call.js';
|
||||||
import { ApiError } from './error.js';
|
import { ApiError } from './error.js';
|
||||||
|
|
||||||
export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise<void>((res) => {
|
export async function handler(endpoint: IEndpoint, ctx: Koa.Context): Promise<void> {
|
||||||
const body = ctx.is('multipart/form-data')
|
const body = ctx.is('multipart/form-data')
|
||||||
? (ctx.request as any).body
|
? (ctx.request as any).body
|
||||||
: ctx.method === 'GET'
|
: ctx.method === 'GET'
|
||||||
? ctx.query
|
? ctx.query
|
||||||
: ctx.request.body;
|
: ctx.request.body;
|
||||||
|
|
||||||
const reply = (x?: any, y?: ApiError) => {
|
const error = (e: ApiError): void => {
|
||||||
if (x == null) {
|
ctx.status = e.httpStatusCode ?? 500;
|
||||||
ctx.status = 204;
|
if (e.httpStatusCode === 401) {
|
||||||
} else if (typeof x === 'number' && y) {
|
ctx.response.set('WWW-Authenticate', 'Bearer');
|
||||||
ctx.status = x;
|
}
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
error: {
|
error: {
|
||||||
message: y!.message,
|
message: e!.message,
|
||||||
code: y!.code,
|
code: e!.code,
|
||||||
id: y!.id,
|
...(e!.info ? { info: e!.info } : {}),
|
||||||
kind: y!.kind,
|
endpoint: endpoint.name,
|
||||||
...(y!.info ? { info: y!.info } : {}),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
// 文字列を返す場合は、JSON.stringify通さないとJSONと認識されない
|
|
||||||
ctx.body = typeof x === 'string' ? JSON.stringify(x) : x;
|
|
||||||
}
|
}
|
||||||
res();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Authentication
|
// Authentication
|
||||||
// for GET requests, do not even pass on the body parameter as it is considered unsafe
|
// for GET requests, do not even pass on the body parameter as it is considered unsafe
|
||||||
authenticate(ctx.headers.authorization, ctx.method === 'GET' ? null : body['i']).then(([user, app]) => {
|
await authenticate(ctx.headers.authorization, ctx.method === 'GET' ? null : body['i']).then(async ([user, app]) => {
|
||||||
// API invoking
|
// API invoking
|
||||||
call(endpoint.name, user, app, body, ctx).then((res: any) => {
|
await call(endpoint.name, user, app, body, ctx).then((res: any) => {
|
||||||
if (ctx.method === 'GET' && endpoint.meta.cacheSec && !body['i'] && !user) {
|
if (ctx.method === 'GET' && endpoint.meta.cacheSec && !body['i'] && !user) {
|
||||||
ctx.set('Cache-Control', `public, max-age=${endpoint.meta.cacheSec}`);
|
ctx.set('Cache-Control', `public, max-age=${endpoint.meta.cacheSec}`);
|
||||||
}
|
}
|
||||||
reply(res);
|
if (res == null) {
|
||||||
|
ctx.status = 204;
|
||||||
|
} else {
|
||||||
|
ctx.status = 200;
|
||||||
|
// If a string is returned, it must be passed through JSON.stringify to be recognized as JSON.
|
||||||
|
ctx.body = typeof res === 'string' ? JSON.stringify(res) : res;
|
||||||
|
}
|
||||||
}).catch((e: ApiError) => {
|
}).catch((e: ApiError) => {
|
||||||
reply(e.httpStatusCode ? e.httpStatusCode : e.kind === 'client' ? 400 : 500, e);
|
error(e);
|
||||||
});
|
});
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
if (e instanceof AuthenticationError) {
|
if (e instanceof AuthenticationError) {
|
||||||
ctx.response.status = 403;
|
error({
|
||||||
ctx.response.set('WWW-Authenticate', 'Bearer');
|
|
||||||
ctx.response.body = {
|
|
||||||
message: 'Authentication failed: ' + e.message,
|
message: 'Authentication failed: ' + e.message,
|
||||||
code: 'AUTHENTICATION_FAILED',
|
code: 'AUTHENTICATION_FAILED',
|
||||||
id: 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14',
|
id: 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14',
|
||||||
kind: 'client',
|
httpStatusCode: 401,
|
||||||
};
|
});
|
||||||
res();
|
|
||||||
} else {
|
} else {
|
||||||
reply(500, new ApiError());
|
error(new ApiError());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
|
|
@ -11,7 +11,7 @@ import cors from '@koa/cors';
|
||||||
import { Instances, AccessTokens, Users } from '@/models/index.js';
|
import { Instances, AccessTokens, Users } from '@/models/index.js';
|
||||||
import config from '@/config/index.js';
|
import config from '@/config/index.js';
|
||||||
import endpoints from './endpoints.js';
|
import endpoints from './endpoints.js';
|
||||||
import handler from './api-handler.js';
|
import { handler } from './api-handler.js';
|
||||||
import signup from './private/signup.js';
|
import signup from './private/signup.js';
|
||||||
import signin from './private/signin.js';
|
import signin from './private/signin.js';
|
||||||
import signupPending from './private/signup-pending.js';
|
import signupPending from './private/signup-pending.js';
|
||||||
|
|
Loading…
Reference in a new issue