From 14cded061f3de4d28d92c39fe032a5cf730dbc2e Mon Sep 17 00:00:00 2001 From: Benny Samir Hierl <bennysamir@posteo.de> Date: Sun, 6 Feb 2022 11:23:47 +0100 Subject: [PATCH] #1 error handling improved Signed-off-by: Benny Samir Hierl <bennysamir@posteo.de> --- src/api/config/errors/index.ts | 41 +++++++++++++++++++++++++++++-- src/api/routes/index.ts | 7 +++--- src/api/routes/wishlist/create.ts | 22 +++++------------ src/api/routes/wishlist/update.ts | 35 +++++++++++--------------- src/api/services/prisma/index.ts | 4 +-- 5 files changed, 64 insertions(+), 45 deletions(-) diff --git a/src/api/config/errors/index.ts b/src/api/config/errors/index.ts index 992af1b..9d91200 100644 --- a/src/api/config/errors/index.ts +++ b/src/api/config/errors/index.ts @@ -1,3 +1,40 @@ +import { FastifyRequest, FastifyReply, FastifyError } from 'fastify' +import { Prisma } from '@prisma/client' + +const errorIs = (e: unknown, c: string) => + e instanceof Prisma.PrismaClientKnownRequestError && e.code === c + +export const defaultErrorHandler = ( + error: FastifyError, + request: FastifyRequest, + reply: FastifyReply +) => { + if (error.validation) { + error.code = '400' + reply.send(error) + } else if (errorIs(error, 'P2002')) { + reply.send( + uniqueKeyError( + // @ts-expect-error: Object is possibly 'undefined' + `${error.meta.target[0] || 'One of the fields'} has to be unique` + ) + ) + } else if (errorIs(error, 'P2025')) { + reply.callNotFound() + } else { + request.log.error(error) + const e = new httpError('unexpected error', 500, '500') + reply.send(e) + } +} + +export const notFoundHandler = ( + request: FastifyRequest, + reply: FastifyReply +) => { + reply.send(notFoundError()) +} + class httpError extends Error { code: string statusCode: number @@ -10,10 +47,10 @@ class httpError extends Error { } } -export const notFoundError = () => { +const notFoundError = () => { return new httpError('Not Found', 404, '404') } -export const uniqueKeyError = (msg: string, code = '4001') => { +const uniqueKeyError = (msg: string, code = '4001') => { return new httpError(msg, 422, code) } diff --git a/src/api/routes/index.ts b/src/api/routes/index.ts index a4dbf16..d88f405 100644 --- a/src/api/routes/index.ts +++ b/src/api/routes/index.ts @@ -1,14 +1,13 @@ import { FastifyInstance } from 'fastify' import { default as wishlistRoute } from './wishlist/' -import { notFoundError } from '../config/errors' +import { defaultErrorHandler, notFoundHandler } from '../config/errors' export default { register: (app: FastifyInstance) => { return app.register( async (app) => { - app.setNotFoundHandler((request, reply) => { - reply.send(notFoundError()) - }) + await app.setNotFoundHandler(notFoundHandler) + await app.setErrorHandler(defaultErrorHandler) await app.register(wishlistRoute, { prefix: '/wishlist' }) }, { prefix: '/api' } diff --git a/src/api/routes/wishlist/create.ts b/src/api/routes/wishlist/create.ts index 55a5087..cf8117b 100644 --- a/src/api/routes/wishlist/create.ts +++ b/src/api/routes/wishlist/create.ts @@ -1,8 +1,6 @@ import { Wishlist, WishlistItem } from '@/types' import { FastifyRequest, FastifyReply, RouteOptions } from 'fastify' import { wishlist } from '../../models' -import { prisma } from '../../services' -import { uniqueKeyError } from '../../config/errors' import { wishlistItemRequestSchema, wishlistItemResponseSchema, @@ -25,13 +23,6 @@ export const createList = <RouteOptions>{ 201: wishlistResponseSchema, }, }, - errorHandler: (error, request, reply) => { - if (error instanceof prisma.errorType && error.code === 'P2002') { - return reply.send(uniqueKeyError('Slugtext has to be unique')) - } - request.log.error(error) - reply.send(new Error('Unexptected Error')) - }, handler: async (request: FastifyRequest, reply: FastifyReply) => { request.log.debug(request.body) const item = await wishlist.create(request.body as Wishlist) @@ -44,17 +35,16 @@ export const createItem = <RouteOptions>{ url: '/:wishlistId/item', schema: { body: wishlistItemRequestSchema, + params: { + type: 'object', + properties: { + wishlistId: { type: 'string' }, + }, + }, response: { 201: wishlistItemResponseSchema, }, }, - errorHandler: (error, request, reply) => { - if (error instanceof prisma.errorType && error.code === 'P2025') { - return reply.callNotFound() - } - request.log.error(error) - reply.send(new Error('Unexptected Error')) - }, handler: async (request: createItemRequest, reply: FastifyReply) => { request.log.debug(request.body) const item = await wishlist.createItem( diff --git a/src/api/routes/wishlist/update.ts b/src/api/routes/wishlist/update.ts index be8224c..78d78fb 100644 --- a/src/api/routes/wishlist/update.ts +++ b/src/api/routes/wishlist/update.ts @@ -1,5 +1,3 @@ -import { uniqueKeyError } from '../../config/errors' -import { prisma } from '../../services' import { Wishlist } from '@/types' import { FastifyRequest, FastifyReply, RouteOptions } from 'fastify' import { wishlist } from '../../models' @@ -28,20 +26,16 @@ export const updateList = <RouteOptions>{ url: '/:wishlistId', schema: { body: wishlistRequestSchema, + params: { + type: 'object', + properties: { + wishlistId: { type: 'string' }, + }, + }, response: { 200: wishlistResponseSchema, }, }, - errorHandler: (error, request, reply) => { - if (error instanceof prisma.errorType && error.code === 'P2002') { - return reply.send(uniqueKeyError('Slugtext has to be unique')) - } - if (error instanceof prisma.errorType && error.code === 'P2025') { - return reply.callNotFound() - } - request.log.error(error) - reply.send(new Error('Unexptected Error')) - }, handler: async (request: updateRequest, reply: FastifyReply) => { request.log.debug(request.body) const item = await wishlist.update( @@ -57,20 +51,21 @@ export const updateItem = <RouteOptions>{ url: '/:wishlistId/item/:itemId', schema: { body: wishlistItemRequestSchema, + params: { + type: 'object', + properties: { + wishlistId: { type: 'string' }, + itemId: { type: 'number' }, + }, + }, response: { 200: wishlistItemResponseSchema, }, }, handler: async (request: updateItemRequest, reply: FastifyReply) => { request.log.debug(request.body) - const item = await wishlist.updateItem( - Number(request.params.itemId), - request.body + reply.send( + await wishlist.updateItem(Number(request.params.itemId), request.body) ) - if (item) { - reply.send(item) - } else { - reply.callNotFound() - } }, } diff --git a/src/api/services/prisma/index.ts b/src/api/services/prisma/index.ts index 9716a39..3134896 100644 --- a/src/api/services/prisma/index.ts +++ b/src/api/services/prisma/index.ts @@ -1,9 +1,7 @@ -import { PrismaClient, Prisma } from '@prisma/client' +import { PrismaClient } from '@prisma/client' const client = new PrismaClient() -const errorType = Prisma.PrismaClientKnownRequestError export default { client, - errorType, }