|
- import { FastifyReply, FastifyRequest } from 'fastify'
-
- type AppErrorOptions = {
- cause?: Error,
- }
-
- export class AppError extends Error {
- public readonly cause?: Error
-
- constructor(message?: string, options?: AppErrorOptions) {
- super(message)
- if (typeof options === 'object') {
- this.cause = options.cause
- }
- }
- }
-
- const httpErrorClassFactory = (statusCode: number, statusMessage?: string) => class HttpError extends AppError {
- readonly statusCode = statusCode
- readonly statusMessage = statusMessage
- }
-
- interface CustomFastifyError extends Error {
- statusMessage?: string;
- validation: {
- keyword: string,
- instancePath: string,
- params: Record<string, unknown>,
- message: string,
- }[];
- statusCode?: number;
- errors: Record<string, unknown>[];
- detail?: string;
- }
-
- export const fastifyErrorHandler = (error: CustomFastifyError, _request: FastifyRequest, reply: FastifyReply) => {
- reply.headers({
- 'Content-Type': 'application/problem+json',
- })
-
- if (error.validation) {
- reply.status(400)
- reply.raw.statusMessage = 'Invalid Request'
- reply.send({
- title: 'There are errors in the request body.',
- 'invalid-params': error.validation.map(v => ({
- name: (
- v.keyword === 'required'
- ? `${v.instancePath}/${v.params.missingProperty}`
- : v.instancePath
- ).replaceAll('/', '.'),
- reason: v.message,
- })),
- })
- return
- }
-
- if (Number.isNaN(reply.raw.statusCode)) {
- reply.status(error?.statusCode ?? 500)
- }
- reply.raw.statusMessage = error.statusMessage ?? 'Unknown Error'
- reply.send({
- title: reply.raw.statusMessage,
- detail: error.message,
- })
- }
-
- export { httpErrorClassFactory as HttpError }
|