From 0a638ed4b7976ade8e162ceba4aec22e5088854a Mon Sep 17 00:00:00 2001 From: Carlo Minotti <50220438+minottic@users.noreply.github.com> Date: Thu, 5 Feb 2026 08:50:49 +0100 Subject: [PATCH] feat: add interceptor to bypass serialization for heavy resp --- .../interceptors/fast-response.interceptor.ts | 30 +++++++++++++++++++ .../published-data.controller.ts | 9 ++++-- .../published-data.v4.controller.ts | 9 ++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 src/published-data/interceptors/fast-response.interceptor.ts diff --git a/src/published-data/interceptors/fast-response.interceptor.ts b/src/published-data/interceptors/fast-response.interceptor.ts new file mode 100644 index 000000000..55e3da791 --- /dev/null +++ b/src/published-data/interceptors/fast-response.interceptor.ts @@ -0,0 +1,30 @@ +import { + Injectable, + NestInterceptor, + ExecutionContext, + CallHandler, +} from "@nestjs/common"; +import { Observable } from "rxjs"; +import { map } from "rxjs/operators"; +import { Response } from "express"; + +@Injectable() +export class FastResponseInterceptor implements NestInterceptor { + constructor( + private readonly headers = { "Content-Type": "application/json" }, + ) {} + + intercept(context: ExecutionContext, next: CallHandler): Observable { + const res = context.switchToHttp().getResponse(); + + return next.handle().pipe( + map((data) => { + if (res.headersSent) return data; + + res.set(this.headers); + res.send(JSON.stringify(data)); + return null; + }), + ); + } +} diff --git a/src/published-data/published-data.controller.ts b/src/published-data/published-data.controller.ts index a06d3481d..9d8707dab 100644 --- a/src/published-data/published-data.controller.ts +++ b/src/published-data/published-data.controller.ts @@ -68,11 +68,11 @@ import { PublishedDataService } from "./published-data.service"; import { PublishedData } from "./schemas/published-data.schema"; import { V3_FILTER_PIPE } from "./pipes/filter.pipe"; import { Filter } from "src/datasets/decorators/filter.decorator"; +import { FastResponseInterceptor } from "./interceptors/fast-response.interceptor"; @ApiBearerAuth() @ApiTags("published data") @Controller("publisheddata") -@UseInterceptors(ClassSerializerInterceptor) export class PublishedDataController { constructor( private readonly attachmentsService: AttachmentsService, @@ -239,6 +239,7 @@ export class PublishedDataController { description: "This endpoint is deprecated and v4 endpoints should be used in the future", }) + @UseInterceptors(new FastResponseInterceptor(), ClassSerializerInterceptor) @SerializeOptions({ type: PublishedDataObsoleteDto, excludeExtraneousValues: true, @@ -276,6 +277,7 @@ export class PublishedDataController { isArray: true, description: "Results with a published documents array", }) + @UseInterceptors(new FastResponseInterceptor(), ClassSerializerInterceptor) @SerializeOptions({ type: PublishedDataObsoleteDto, excludeExtraneousValues: true, @@ -408,11 +410,12 @@ export class PublishedDataController { status: HttpStatus.NOT_FOUND, description: "PublishedData not found", }) - @Get("/:id") + @UseInterceptors(new FastResponseInterceptor(), ClassSerializerInterceptor) @SerializeOptions({ type: PublishedDataObsoleteDto, excludeExtraneousValues: true, }) + @Get("/:id") async findOne( @Param(new IdToDoiPipe(), RegisteredPipe) filter: { @@ -449,6 +452,7 @@ export class PublishedDataController { isArray: false, description: "Return updated published data", }) + @UseInterceptors(new FastResponseInterceptor(), ClassSerializerInterceptor) @SerializeOptions({ type: PublishedDataObsoleteDto, excludeExtraneousValues: true, @@ -485,6 +489,7 @@ export class PublishedDataController { isArray: false, description: "Return removed published data", }) + @UseInterceptors(new FastResponseInterceptor(), ClassSerializerInterceptor) @SerializeOptions({ type: PublishedDataObsoleteDto, excludeExtraneousValues: true, diff --git a/src/published-data/published-data.v4.controller.ts b/src/published-data/published-data.v4.controller.ts index 824a7829a..572bf3055 100644 --- a/src/published-data/published-data.v4.controller.ts +++ b/src/published-data/published-data.v4.controller.ts @@ -13,6 +13,7 @@ import { Query, Req, UseGuards, + UseInterceptors, } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import { @@ -58,6 +59,7 @@ import { } from "./schemas/published-data.schema"; import { V4_FILTER_PIPE } from "./pipes/filter.pipe"; import { ILimitsFilter } from "src/common/interfaces/common.interface"; +import { FastResponseInterceptor } from "./interceptors/fast-response.interceptor"; @ApiBearerAuth() @ApiTags("published data v4") @@ -116,6 +118,7 @@ export class PublishedDataV4Controller { isArray: true, description: "Results with a published documents array", }) + @UseInterceptors(new FastResponseInterceptor()) async findAll( @Req() request: Request, @Query(...V4_FILTER_PIPE, RegisteredFilterPipe) @@ -307,6 +310,7 @@ export class PublishedDataV4Controller { status: HttpStatus.NOT_FOUND, description: "PublishedData not found", }) + @UseInterceptors(new FastResponseInterceptor()) @Get("/:id") async findOne( @Req() request: Request, @@ -334,6 +338,7 @@ export class PublishedDataV4Controller { isArray: false, description: "Return updated published data with id specified", }) + @UseInterceptors(new FastResponseInterceptor()) @Patch("/:id") async update( @Req() request: Request, @@ -389,6 +394,7 @@ export class PublishedDataV4Controller { isArray: false, description: "Return published data with id specified after publishing", }) + @UseInterceptors(new FastResponseInterceptor()) @Post("/:id/publish") async publish( @Req() request: Request, @@ -437,6 +443,7 @@ export class PublishedDataV4Controller { isArray: false, description: "Return amended data with id specified", }) + @UseInterceptors(new FastResponseInterceptor()) @Post("/:id/amend") async amend( @Req() request: Request, @@ -504,6 +511,7 @@ export class PublishedDataV4Controller { @CheckPolicies("publisheddata", (ability: AppAbility) => ability.can(Action.Delete, PublishedData), ) + @UseInterceptors(new FastResponseInterceptor()) @Delete("/:id") async remove( @Req() request: Request, @@ -547,6 +555,7 @@ export class PublishedDataV4Controller { @CheckPolicies("publisheddata", (ability: AppAbility) => ability.can(Action.Update, PublishedData), ) + @UseInterceptors(new FastResponseInterceptor()) @Post("/:id/register") async register( @Req() request: Request,