diff --git a/package.json b/package.json index 75519d1a185803bc5f195ae48fccf8593021cded..37f66f78cbed369f51f01c858c2c9eb87d2f9fc5 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@nestjs/platform-express": "^9.0.0", "class-transformer": "^0.5.1", "class-validator": "^0.13.2", + "fastify": "^4.9.2", "mongoose": "^6.7.2", "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", diff --git a/src/groups/groups.controller.ts b/src/groups/groups.controller.ts index c9be0429accafe4e9e246edd99edcf516ae4c5ed..5eff7b8b3453ca71a19625a70adca3cf6114f7d3 100644 --- a/src/groups/groups.controller.ts +++ b/src/groups/groups.controller.ts @@ -6,14 +6,17 @@ import { Delete, Param, Body, + UseInterceptors, } from '@nestjs/common'; import { Observable } from 'rxjs'; +import { HttpInterceptor } from '../interceptors/http.interceptor'; import { CreateGroupDto } from './dto/create-group.dto'; import { UpdateGroupDto } from './dto/update-group.dto'; import { GroupEntity } from './entities/group.entity'; import { GroupsService } from './groups.service'; @Controller('groups') +@UseInterceptors(HttpInterceptor) export class GroupsController { constructor(private readonly _groupsService: GroupsService) {} diff --git a/src/groups/groups.module.ts b/src/groups/groups.module.ts index 3320cf0c09744da9567ab8e266c5d7460f034792..b8c3b67845ab5cae0b2b67166bcd743a88abd817 100644 --- a/src/groups/groups.module.ts +++ b/src/groups/groups.module.ts @@ -1,4 +1,4 @@ -import { Module } from '@nestjs/common'; +import { Module, Logger } from '@nestjs/common'; import { MongooseModule } from '@nestjs/mongoose'; import { GroupsDao } from './dao/groups.dao'; import { GroupsController } from './groups.controller'; @@ -10,6 +10,6 @@ import { Group, GroupSchema } from './schemas/group.schema'; MongooseModule.forFeature([{ name: Group.name, schema: GroupSchema }]), ], controllers: [GroupsController], - providers: [GroupsService, GroupsDao], + providers: [GroupsService, GroupsDao, Logger], }) export class GroupsModule {} diff --git a/src/interceptors/http.interceptor.ts b/src/interceptors/http.interceptor.ts new file mode 100644 index 0000000000000000000000000000000000000000..ebef03fe0ef69906c7693c2f8463ef75f03e819d --- /dev/null +++ b/src/interceptors/http.interceptor.ts @@ -0,0 +1,59 @@ +import { + CallHandler, + ExecutionContext, + Injectable, + Logger, + NestInterceptor, +} from '@nestjs/common'; +import { merge, Observable, of } from 'rxjs'; +import { filter, map, mergeMap, tap } from 'rxjs/operators'; +import { FastifyReply } from 'fastify'; + +@Injectable() +export class HttpInterceptor implements NestInterceptor { + /** + * Class constructor + * @param _logger + */ + constructor(private readonly _logger: Logger) {} + + /** + * Intercepts all HTTP requests and responses + * + * @param context + * @param next + */ + intercept = ( + context: ExecutionContext, + next: CallHandler, + ): Observable<any> => { + const cls = context.getClass(); + const handler = context.getHandler(); + const response: FastifyReply = context + .switchToHttp() + .getResponse<FastifyReply>(); + const logCtx = `${cls.name}.${handler.name}`; + + return next.handle().pipe( + map((_) => of(_)), + mergeMap((obs: Observable<any>) => + merge( + obs.pipe( + filter((_) => !!_), + map((_) => _), + ), + obs.pipe( + filter((_) => !_), + tap(() => response.status(204)), + map((_) => _), + ), + ), + ), + tap({ + next: (_) => + this._logger.log(!!_ ? JSON.stringify(_) : 'NO CONTENT', logCtx), + error: (_) => this._logger.error(_.message, JSON.stringify(_), logCtx), + }), + ); + }; +}