Backend Error Handling
Service Pattern
async getById(id: string) {
try {
const item = await this.prisma.feature.findUnique({ where: { id } });
if (!item) throw new CustomHttpException('Not found', HttpStatus.NOT_FOUND);
return item;
} catch (error) {
handleException(error, false, {});
}
}
Every public service method uses try/catch → handleException.
Throw Business Errors
throw new CustomHttpException('Slug already exists', HttpStatus.BAD_REQUEST);
throw new CustomHttpException('Not found', HttpStatus.NOT_FOUND);
throw new CustomForbiddenException('Must be admin');
Response Helpers
// Single entity
return sendSuccessfulResponse(data);
// → { status: 'success', data }
// List with count
return sendCustomResponse({ data: requests, count });
// → { status: 'success', data, count }
// Custom fields
return sendCustomResponse({ data, count, types });
Never return raw Prisma objects from controllers.
Global Filters
Register once in app.module.ts:
{ provide: APP_FILTER, useClass: AllExceptionsFilter },
{ provide: APP_FILTER, useClass: PrismaExceptionFilter },
| Filter | Handles |
|---|---|
AllExceptionsFilter |
HttpException → log → handleException |
PrismaExceptionFilter |
P2002 unique, P2025 not found → { data: { errorMessage } } |
Error Response Shapes
| Type | Shape |
|---|---|
| Business | { status: 'error', key, data } |
| Prisma | { data: { errorMessage, errorTarget? } } |
| Database P2002 | key: SOMETHING_WENT_WRONG_DATABASE_P2002 |
Custom Exceptions
CustomHttpException, CustomBadRequestException, CustomNotFoundException, CustomForbiddenException — flag customError: true skips verbose logging.
Logging
File logs in logs/ — daily rotation. LoggingInterceptor for request timing. Uncaught → logs/uncaughtException.txt.