I have a global interceptor that needs to initialize my own request context DTO and I want this DTO to be accessible in Controller which handles the current request.
The solution i found so far is to create Request scoped injectable RequestContext class:
import {
Injectable,
Scope
} from '@nestjs/common';
import { Request } from 'express';
import { IncomingHttpHeaders } from 'http';
@Injectable({ scope: Scope.REQUEST })
export class RequestContext {
public headers: IncomingHttpHeaders;
....
initialize(request: Request) {
this.headers = request.headers;
.....
}
}
And inject this class into the interceptor:
import {
NestInterceptor,
ExecutionContext,
CallHandler,
Injectable,
Inject
} from '@nestjs/common';
import { Request } from 'express';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { RequestContext } from '../dto';
@Injectable()
export class RequestContextInterceptor implements NestInterceptor {
constructor(
@Inject(RequestContext)
protected requestContext: RequestContext
) { }
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest<Request>();
this.requestContext.initialize(request);
return next.handle()
.pipe(
tap(() => {
// decorate response
}));
}
}
And then inject this RequestContext in each controller...
import {
Controller,
UseInterceptors,
Inject,
Get
} from '@nestjs/common';
import { BaseMicroserviceController } from '../core/base/base-microservice.controller';
import { RequestContext } from '../dto';
import { DispatchService } from '../services';
@Controller('api/v1/example')
export class ExampleController extends BaseMicroserviceController {
constructor (
@Inject(RequestContext)
protected requestContext: RequestContext,
protected dispatcheService: DispatchService
) {
super(dispatcheService);
}
@Get()
test() {
return 'test';
}
}
There is huge workaround to achieve this simple functionality IMHO In addition, I have this article which describes why to use Scope based injection is not good: https://guxi.me/posts/why-you-should-avoid-using-request-scope-injection-in-nest-js/
My service will be huge, with a huge amount of controllers and a huge amount of injectable services. According to this article - my service will be not scalable in terms of performance and memory usage.
My question is how to achieve the functionality I need in NestJS and what is the best practice?
Another "bonus question" - the RequestContext class has initialize method which receives express Request and parses it. I don't like it, I want each property of this class to be read-only and initialize this class in a traditional way by calling the constructor with request object... How I can achieve it with @Inject strategy?