Files
reader/server/src/http/errors.ts
T

35 lines
1.4 KiB
TypeScript

import type { FastifyInstance } from 'fastify';
import { AppError, RateLimitError } from '../lib/errors.ts';
/**
* Single error serialiser. Responses intentionally keep the same shape across
* every endpoint so old clients keep working as the API grows (§8.3).
*/
export function registerErrorHandler(app: FastifyInstance): void {
app.setErrorHandler((error, request, reply) => {
if (error instanceof AppError) {
if (error instanceof RateLimitError) reply.header('retry-after', error.retryAfter);
reply.status(error.statusCode).send({ error: { code: error.code, message: error.message } });
return;
}
const fastifyError = error as { statusCode?: number; message?: string };
const status = fastifyError.statusCode ?? 500;
if (status >= 500) {
request.log.error({ err: error }, 'unhandled error');
reply.status(status).send({ error: { code: 'INTERNAL', message: 'internal server error' } });
return;
}
// Validation and content-type failures land here; they are the client's
// fault, so the message is passed through verbatim.
reply.status(status).send({
error: { code: 'BAD_REQUEST', message: fastifyError.message || 'bad request' },
});
});
app.setNotFoundHandler((request, reply) => {
reply.status(404).send({
error: { code: 'NOT_FOUND', message: `no route for ${request.method} ${request.url}` },
});
});
}