Creating dynamic NestJS Providers/Services based on Request params for multitenancy
2 min read

Creating dynamic NestJS Providers/Services based on Request params for multitenancy

Creating dynamic NestJS Providers/Services based on Request params for multitenancy

Sometimes you need access the request scope in NestJS for getting parameters and data from the request being made in order to inject the appropriate Service.

With Nest@7 (released with version 6 btw.) we can define providers's scope, the scope can be SINGLETON, REQUEST or TRANSIENT. The default one is Singleton, but for accessing the request data we'll need to declare our service to be instatiated on the Request scope. For doing this is as easy as modify the @Inject() decorator:

@Injectable({ scope: Scope.REQUEST })

Dynamic module genereated by a Factory

We have different paths for coding a dynamic service in Nest, but I think for this example a Factory would be the cleanest way to do it.

Basically with a factory, we execute a function and this function creates and returns the appropriate Service, the function itself is the Factory.

Usually the factory is coded in a separate class or file, but for simplifying things I will put it on the Database Module:

const databaseConnectionFactory = {
  provide: 'DBCONNECTION',
  scope: Scope.REQUEST,
  useFactory: (req) => {
    const headers = req.headers;
    return Nano.default('string conn param')
  inject: [REQUEST],

With the previous snippet we're declaring a new Factory for creating dynamic database connections. As you can see, we are injecting the REQUEST nestJS core object wich it'll hold the request metadata, allowing us to consume the request parameters.

The returned value will be the injected one.

Declaring the Factory in the Module

In the previous section we've created the Factory, and we've called the provider DBCONNECTION in the provide entry.

For using this provider, we only need to add it as provider in the desired Module and to export it if the DBCONNECTION needs to be injected from outside this module:

  providers: [databaseConnectionFactory],
  exports: ['DBCONNECTION', TenantService]
export class DatabaseModule {}

Using the custom dynamic provider

For using the provider we only have to call the @Inject decorator inside the constructor of the service which need this provider:

constructor(@Inject('DBCONNECTION') connection) {
    this.tenantsDB = connection.use('tenants')

You can find more information here:

Documentation | NestJS - A progressive Node.js framework
Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Progamming), FP (Functional Programming), and FRP (Functional Reactive Programming).