Quick Start
Background
This library exposes a dynamic ClsModule
which exposes the injectable ClsService
and provides means to setting up and interacting with the CLS context.
The CLS context is a storage that wraps around a chain of function calls. It can be accessed anywhere during the lifecycle of such chain via the ClsService
.
Example
Below is an example of using this library to store the client's IP address in an interceptor and retrieving it in a service without explicitly passing it along.
This example assumes you are using HTTP and therefore can use middleware. For usage with non-HTTP transports, see Setting up CLS context.
Register the ClsModule
Register the ClsModule
and automatically mount the ClsMiddleware
which wraps the entire request in a shared CLS context on all routes.
@Module({
imports: [
ClsModule.forRoot({
global: true,
middleware: { mount: true },
}),
],
providers: [AppService],
controllers: [AppController],
})
export class AppModule {}
Create IP-address interceptor
Create an interceptor that
- injects the
ClsService
to get access to the current shared CLS context, - extract the users's IP address from the request and stores it into the CLS context,
@Injectable()
export class UserIpInterceptor implements NestInterceptor {
constructor(private readonly cls: ClsService) {}
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest();
const userIp = request.connection.remoteAddress;
this.cls.set('ip', userIp);
return next.handle();
}
}
Mount interceptor to controller
By mounting the UserIpInterceptor
on the controller, it gets access to the same shared CLS context that the ClsMiddleware
set up.
Of course, we could also bind the interceptor globally with APP_INTERCEPTOR
.
@UseInterceptors(UserIpInterceptor)
@Injectable()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get('/hello')
hello() {
return this.appService.sayHello();
}
}
Access CLS context in service
In the AppService
, we can retrieve the user's IP from the CLS context without explicitly passing in anything, and without making the AppService
request-scoped!
@Injectable()
export class AppService {
constructor(private readonly cls: ClsService) {}
sayHello() {
const userIp = this.cls.get('ip');
return 'Hello ' + userIp + '!';
}
}
That's it
This is pretty much all there is to it. This library further provides more quality-of-life features, so read on!
If your use-case is really simple, you can instead consider creating a custom implementation with AsyncLocalStorage
. Limiting the number of dependencies in your application is always a good idea!