Introduction
In NestJS, services encapsulate business logic and can be shared across different parts of your application. However, when services are defined in different modules, you need to understand the module dependency injection system to use them. This tutorial will guide you on how to inject a service from one module into another within a NestJS application using the latest syntax and TypeScript best practices.
Prerequisites
Before you begin, ensure you have the following installed:
- Node.js (14.x or later)
- NestJS CLI
- TypeScript
Ensure you’re familiar with TypeScript and the basics of NestJS, including modules, controllers, and services (providers).
Creating Your Modules and Services
First, let’s create two modules: UsersModule
and OrdersModule
. The UsersService
from the UsersModule
will be injected into the OrdersModule
.
nest g module Users
nest g module Orders
nest g service Users
nest g service Orders
Exporting the Service
To be able to use UsersService
in OrdersModule
, you must first export it in UsersModule
.
@Module({
providers: [UsersService],
exports: [UsersService]
})
export class UsersModule {}
Importing the Module
Next, import UsersModule
into OrdersModule
to make UsersService
available for injection.
@Module({
imports: [UsersModule],
providers: [OrdersService]
})
export class OrdersModule {}
InjecSystemService
To inject UsersService
into OrdersService
, use the @Injectable()
decorator and specify the dependency in the constructor.
@Injectable()
export class OrdersService {
constructor(private usersService: UsersService) {}
// Your methods using usersService here
}
Advanced Usage: Custom Providers with Module Ref
For advanced scenarios, you might want to manipulate providers or dynamically provide them. Imagine a scenario where you have different implementations based on certain criteria, and you want the consuming module to decide the actual implementation it requires. Here’s a pattern using ModuleRef
to resolve providers dynamically in NestJS.
@Injectable()
export class OrdersService {
private usersService: UsersService;
constructor(private moduleRef: ModuleRef) {
this.usersService = this.moduleRef.get(UsersService, { strict: false });
}
// Your methods using usersService here
}
Understanding the Global Module
Sometimes, you might have a service that should be available throughout your application. You can make a module global with the @Global()
decorator. This should be used sparingly and only for truly application-wide services.
@Global()
@Module({
providers: [CommonService],
exports: [CommonService]
})
export class CommonModule {}
Add the global module to the root module’s imports array, and its services will accessible across the entire application without importing the module in each feature module explicitly.
Conclusion
Understanding service injection across modules is pivotal for structuring your NestJS application effectively. This tutorial covered how to export and import services, advanced dynamic provider techniques with ModuleRef
, and leveraging global modules for widespread services. Remember that keeping your modules and providers well-organized will lead to a maintainable and scalable codebase.