Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nest.js: Circular dependencies in dynamic modules

What is the correct way to import dynamic modules when there's a circular dependency between them? I simply changed forwardRef(() => MyModule) to forwardRef(() => MyModule.forRoot()), and I'm getting Nest can't resolve dependencies error.

like image 465
dols3m Avatar asked Jun 03 '19 18:06

dols3m


People also ask

How do I resolve circular dependency in nest JS?

Avoiding circular dependencies by refactoring The NestJS documentation advises that circular dependencies be avoided where possible. Circular dependencies create tight couplings between the classes or modules involved, which means both classes or modules have to be recompiled every time either of them is changed.

How do you avoid circular dependencies?

To reduce or eliminate circular dependencies, architects must implement loose component coupling and isolate failures. One approach is to use abstraction to break the dependency chain. To do this, you introduce an abstracted service interface that delivers underlying functionality without direct component coupling.

What is dynamic modules in NestJS?

In other words, dynamic modules provide an API for importing one module into another, and customizing the properties and behavior of that module when it is imported, as opposed to using the static bindings we've seen so far.


Video Answer


1 Answers

The best way to deal with nest module dependency is to import dependencies always through modules and never through services. If you run into a circular dependency, nest will show you an error and you can easily fix it with forwardRef().

let say your application has 3 tightly coupled modules.

  • @moduleA()
  • @moduleB()
  • @moduleC()

And two supporting modules

  • @moduleX()
  • @moduleY()
  • @moduleZ()

Also, all modules are exporting services with the same name.

Consider a situation where

@moduleA() imports [serviceB, serviceX]

And

@moduleB() imports [serviceA, serviceY, serviceZ]

Now in @moduleC() if you want to use serivceA() then you will have to

@moduleC() imports [serviceA, serviceB, serviceX, serviceY, serviceZ]

In most cases, nest throws the correct error saying which dependency is missing where. But some times, nest only says dependency at [index] is missing, nest doesn't says where it is missing. This will lead to great level of confusion.

A neat approach is to always import modules

@moduleA() imports [moduleB, moduleX]

@moduleB() imports [moduleA, moduleY, moduleZ]

@moduleC() imports [moduleA]


If nest is complaining again about dependency issue then import modules using forwardRef

@module({
     imports: [
       forwardRef(() => ModuleA)
       ModuleB
       ],
    controllers: [],
    providers: []
})

Sometimes even after doing all these, you may again run into dependency not available error. Then you can use ModuleRef. Let's take the same example where you want to use ServiceA() in ModuleC()

You will then be adding serviceA() to providers[] in ModuleC() and in the serviceC() class you need to add the following.

import { Injectable, OnModuleInit } from '@nestjs/common'; \\need OnModuleInit 
import { ServiceA} from '../FolderA/serviceA.service';

export class ServiceC implements OnModuleInit {
   
   private serviceA: ServiceA;
   constructor(private readonly moduleRef: ModuleRef) {}

   onModuleInit() {
        this.serviceA= this.moduleRef.get(ServiceA);
    }
   
   foo(){
     console.log(this.serviceA.someFunction())
   }
}

Please check more at Official documentation.

like image 152
Anees Hameed Avatar answered Oct 22 '22 04:10

Anees Hameed