Skip to main content

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.

note

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.

app.module.ts
@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,
user-ip.interceptor.ts
@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.

app.controller.ts
@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!

app.service.ts
@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!

info

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!