feat: added response interceptor and exception filter
This commit is contained in:
@@ -0,0 +1,42 @@
|
|||||||
|
import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus, Logger } from "@nestjs/common";
|
||||||
|
import { Request, Response } from "express";
|
||||||
|
|
||||||
|
@Catch()
|
||||||
|
export class AllExceptionFilter implements ExceptionFilter {
|
||||||
|
private readonly logger = new Logger(AllExceptionFilter.name);
|
||||||
|
|
||||||
|
catch(exception: unknown, host: ArgumentsHost): void {
|
||||||
|
const ctx = host.switchToHttp();
|
||||||
|
|
||||||
|
const response = ctx.getResponse<Response>();
|
||||||
|
const request = ctx.getRequest<Request>();
|
||||||
|
|
||||||
|
const status = exception instanceof HttpException
|
||||||
|
? exception.getStatus()
|
||||||
|
: HttpStatus.INTERNAL_SERVER_ERROR
|
||||||
|
|
||||||
|
let message: string | string[] = 'خطای داخلی سرور!';
|
||||||
|
|
||||||
|
if(exception instanceof HttpException) {
|
||||||
|
const exceptionResponse = exception.getResponse();
|
||||||
|
|
||||||
|
if(typeof exceptionResponse === 'string') {
|
||||||
|
message = exceptionResponse;
|
||||||
|
} else if(typeof exceptionResponse === 'object' && exceptionResponse !== null) {
|
||||||
|
message = (exceptionResponse as {message?: string | string[]}).message ?? message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status === HttpStatus.INTERNAL_SERVER_ERROR) {
|
||||||
|
this.logger.error(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
response.status(status).json({
|
||||||
|
success: false,
|
||||||
|
statusCode: status,
|
||||||
|
message,
|
||||||
|
path: request.url,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import {
|
||||||
|
CallHandler,
|
||||||
|
ExecutionContext,
|
||||||
|
Injectable,
|
||||||
|
NestInterceptor,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { ApiResponse } from '../interfaces/api-response.interface';
|
||||||
|
import { map, Observable } from 'rxjs';
|
||||||
|
import { Response } from 'express';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ResponseInterceptor<T> implements NestInterceptor<
|
||||||
|
T,
|
||||||
|
ApiResponse<T>
|
||||||
|
> {
|
||||||
|
intercept(
|
||||||
|
context: ExecutionContext,
|
||||||
|
next: CallHandler,
|
||||||
|
): Observable<ApiResponse<T>> {
|
||||||
|
const response = context.switchToHttp().getResponse<Response>();
|
||||||
|
|
||||||
|
return next.handle().pipe(
|
||||||
|
map((data: T) => ({
|
||||||
|
success: true,
|
||||||
|
statusCode: response.statusCode,
|
||||||
|
message: 'درخواست با موفقیت پاسخ داده شد!',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
data
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export interface ApiResponse<T> {
|
||||||
|
success: boolean;
|
||||||
|
statusCode: number;
|
||||||
|
message: string;
|
||||||
|
timestamp: string;
|
||||||
|
data: T;
|
||||||
|
}
|
||||||
+12
-4
@@ -1,8 +1,14 @@
|
|||||||
import { NestFactory, Reflector } from '@nestjs/core';
|
import { NestFactory, Reflector } from '@nestjs/core';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
import { ClassSerializerInterceptor, Logger, ValidationPipe } from '@nestjs/common';
|
import {
|
||||||
|
ClassSerializerInterceptor,
|
||||||
|
Logger,
|
||||||
|
ValidationPipe,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { setupSwagger } from './config/swagger.config';
|
import { setupSwagger } from './config/swagger.config';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { AllExceptionFilter } from './common/filters/all-exception.filter';
|
||||||
|
import { ResponseInterceptor } from './common/interceptors/response.interceptor';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const logger = new Logger('APP');
|
const logger = new Logger('APP');
|
||||||
@@ -16,14 +22,16 @@ async function bootstrap() {
|
|||||||
transform: true,
|
transform: true,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
app.useGlobalInterceptors(
|
||||||
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));
|
new ResponseInterceptor(),
|
||||||
|
new ClassSerializerInterceptor(app.get(Reflector)),
|
||||||
|
);
|
||||||
|
app.useGlobalFilters(new AllExceptionFilter());
|
||||||
|
|
||||||
setupSwagger(app);
|
setupSwagger(app);
|
||||||
|
|
||||||
const configService = app.get<ConfigService>(ConfigService);
|
const configService = app.get<ConfigService>(ConfigService);
|
||||||
|
|
||||||
|
|
||||||
const PORT = configService.getOrThrow<number>('APP_PORT');
|
const PORT = configService.getOrThrow<number>('APP_PORT');
|
||||||
await app.listen(PORT, '0.0.0.0', () => {
|
await app.listen(PORT, '0.0.0.0', () => {
|
||||||
logger.log(`Server running at http://localhost:${PORT}`);
|
logger.log(`Server running at http://localhost:${PORT}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user