Skip to content

Commit a635f24

Browse files
Feat/error (#998)
* implemented the errors * implemented the errors * implemented the errors * implemented the errors * implemented the errors --------- Co-authored-by: nanaf6203-bit <nanaf6203@gmail.com>
1 parent fd7acb3 commit a635f24

5 files changed

Lines changed: 357 additions & 242 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {
2+
ExceptionFilter,
3+
Catch,
4+
ArgumentsHost,
5+
HttpStatus,
6+
Logger,
7+
} from '@nestjs/common';
8+
import { Request, Response } from 'express';
9+
10+
@Catch()
11+
export class AllExceptionsFilter implements ExceptionFilter {
12+
private readonly logger = new Logger(AllExceptionsFilter.name);
13+
14+
catch(exception: unknown, host: ArgumentsHost) {
15+
const ctx = host.switchToHttp();
16+
const response = ctx.getResponse<Response>();
17+
const request = ctx.getRequest<Request>();
18+
19+
const status = HttpStatus.INTERNAL_SERVER_ERROR;
20+
const message = exception instanceof Error ? exception.message : 'Internal server error';
21+
22+
this.logger.error(
23+
`Uncaught Exception: ${message} - ${request.url}`,
24+
exception instanceof Error ? exception.stack : 'No stack trace available',
25+
);
26+
27+
response.status(status).json({
28+
success: false,
29+
statusCode: status,
30+
timestamp: new Date().toISOString(),
31+
path: request.url,
32+
message: process.env.NODE_ENV === 'production' ? 'Internal server error' : message,
33+
stack: process.env.NODE_ENV === 'development' && exception instanceof Error ? exception.stack : undefined,
34+
});
35+
}
36+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import {
2+
ExceptionFilter,
3+
Catch,
4+
ArgumentsHost,
5+
HttpException,
6+
Logger,
7+
} from '@nestjs/common';
8+
import { Request, Response } from 'express';
9+
10+
@Catch(HttpException)
11+
export class HttpExceptionFilter implements ExceptionFilter {
12+
private readonly logger = new Logger(HttpExceptionFilter.name);
13+
14+
catch(exception: HttpException, host: ArgumentsHost) {
15+
const ctx = host.switchToHttp();
16+
const response = ctx.getResponse<Response>();
17+
const request = ctx.getRequest<Request>();
18+
const status = exception.getStatus();
19+
20+
const exceptionResponse = exception.getResponse();
21+
let message = 'An unexpected error occurred';
22+
let errors = null;
23+
24+
if (typeof exceptionResponse === 'string') {
25+
message = exceptionResponse;
26+
} else if (typeof exceptionResponse === 'object') {
27+
message = (exceptionResponse as any).message || message;
28+
errors = (exceptionResponse as any).errors || null;
29+
}
30+
31+
this.logger.error(
32+
`HTTP Exception: ${status} - ${message} - ${request.url} - Stack: ${exception.stack}`,
33+
);
34+
35+
response.status(status).json({
36+
success: false,
37+
statusCode: status,
38+
timestamp: new Date().toISOString(),
39+
path: request.url,
40+
message,
41+
errors,
42+
stack: process.env.NODE_ENV === 'development' ? exception.stack : undefined,
43+
});
44+
}
45+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import {
2+
ExceptionFilter,
3+
Catch,
4+
ArgumentsHost,
5+
HttpStatus,
6+
Logger,
7+
} from '@nestjs/common';
8+
import { Request, Response } from 'express';
9+
import { Prisma } from '@prisma/client';
10+
11+
@Catch(Prisma.PrismaClientKnownRequestError)
12+
export class PrismaExceptionFilter implements ExceptionFilter {
13+
private readonly logger = new Logger(PrismaExceptionFilter.name);
14+
15+
catch(exception: Prisma.PrismaClientKnownRequestError, host: ArgumentsHost) {
16+
const ctx = host.switchToHttp();
17+
const response = ctx.getResponse<Response>();
18+
const request = ctx.getRequest<Request>();
19+
20+
let status = HttpStatus.INTERNAL_SERVER_ERROR;
21+
let message = 'Database error occurred';
22+
let errors = null;
23+
24+
// Handle common Prisma errors
25+
switch (exception.code) {
26+
case 'P2002': // Unique constraint violation
27+
status = HttpStatus.CONFLICT;
28+
const target = (exception.meta?.target as string[])?.join(', ') || 'field';
29+
message = `Unique constraint failed on ${target}`;
30+
errors = { [target]: 'must be unique' };
31+
break;
32+
case 'P2025': // Record not found
33+
status = HttpStatus.NOT_FOUND;
34+
message = 'Record not found';
35+
break;
36+
case 'P2003': // Foreign key constraint violation
37+
status = HttpStatus.BAD_REQUEST;
38+
message = 'Foreign key constraint failed - related record does not exist';
39+
break;
40+
case 'P2014': // Relation violation
41+
status = HttpStatus.BAD_REQUEST;
42+
message = 'Invalid relation - cannot change record due to existing dependencies';
43+
break;
44+
case 'P2000': // Value too long for column
45+
status = HttpStatus.BAD_REQUEST;
46+
message = 'Value too long for column';
47+
break;
48+
case 'P2011': // Null constraint violation
49+
status = HttpStatus.BAD_REQUEST;
50+
message = 'Null constraint violation - cannot set required field to null';
51+
break;
52+
default:
53+
this.logger.error(`Unhandled Prisma error: ${exception.code}`, exception.stack);
54+
}
55+
56+
this.logger.error(
57+
`Prisma Exception: ${exception.code} - ${message} - ${request.url} - Stack: ${exception.stack}`,
58+
);
59+
60+
response.status(status).json({
61+
success: false,
62+
statusCode: status,
63+
timestamp: new Date().toISOString(),
64+
path: request.url,
65+
message,
66+
errors,
67+
prismaCode: process.env.NODE_ENV === 'development' ? exception.code : undefined,
68+
stack: process.env.NODE_ENV === 'development' ? exception.stack : undefined,
69+
});
70+
}
71+
}

src/main.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ import { RateLimitHeadersInterceptor } from './auth/interceptors/rate-limit-head
1313
import { ResponseFormatInterceptor } from './common/interceptors/response-format.interceptor';
1414
import { setupSwagger } from './config/swagger.config';
1515
import { validateEnvironment } from './utils/validate-env';
16+
// Import our exception filters
17+
import { AllExceptionsFilter } from './common/filters/all-exceptions.filter';
18+
import { HttpExceptionFilter } from './common/filters/http-exception.filter';
19+
import { PrismaExceptionFilter } from './common/filters/prisma-exception.filter';
1620

1721
async function bootstrap() {
1822
validateEnvironment();

0 commit comments

Comments
 (0)