22 lines
1.3 KiB
TypeScript
22 lines
1.3 KiB
TypeScript
import { randomUUID } from 'node:crypto';
|
|
import { sendOpenApiProblem, type OpenApiProblemResponse } from './open-api.protocol';
|
|
|
|
/** Mounted after parsers, before routes; never expose parser errors containing raw input. */
|
|
export function openApiBodyErrorMiddleware(
|
|
error: unknown,
|
|
request: { openApiRequestId?: string },
|
|
response: OpenApiProblemResponse,
|
|
next: (error: unknown) => void,
|
|
) {
|
|
const type = error && typeof error === 'object' && 'type' in error ? error.type : undefined;
|
|
const failures: Record<string, { status: number; code: string; message: string }> = {
|
|
'entity.parse.failed': { status: 400, code: 'PARAMETER_INVALID', message: '请求体必须为有效的JSON对象' },
|
|
'entity.too.large': { status: 413, code: 'PAYLOAD_TOO_LARGE', message: '请求体超过大小限制' },
|
|
'charset.unsupported': { status: 415, code: 'UNSUPPORTED_MEDIA_TYPE', message: '请求体字符集不受支持' },
|
|
'encoding.unsupported': { status: 415, code: 'UNSUPPORTED_MEDIA_TYPE', message: '请求体编码不受支持' },
|
|
};
|
|
const failure = typeof type === 'string' && Object.hasOwn(failures, type) ? failures[type] : undefined;
|
|
if (!failure) return next(error);
|
|
sendOpenApiProblem(response, (request.openApiRequestId ??= `req_${randomUUID()}`), failure);
|
|
}
|