Dependency injection in NestJS
What is Dependency Injection (DI)?
Dependency injection is a programming pattern where dependencies needed in a class or funciton are passed in as parameters instead of being instantiated inside the class/function.
DI allows a class to receive its dependencies from outside, rather than creating them itself. This way, the class does not need to know the details of how its dependencies are created, which promotes loose coupling.
How Does DI Work in NestJS?
In NestJS, Dependency Injection is a core feature built into the framework. It allows us to easily manage and inject dependencies into classes such as controllers, services, and other providers.
Providers: any class annotated with the
@Injectable()
decorator can be treated as a provider and can be injected into other classes using DI.Modules: providers are typically declared within modules, and the DI system uses the module's metadata to resolve and inject dependencies.
Injecting Dependencies: dependencies are injected into classes using the constructor. When you define a dependency in a class constructor, NestJS will automatically resolve and inject the required instance.
Here’s an example of 2 providers, a user service and an auth service.
AuthService
is a provider (service) that depends on UsersService
. Instead of the auth service creating an instance of UsersService
itself, the AuthService
has it injected via the constructor.
import { Injectable } from '@nestjs/common';
@Injectable()
export class UsersService {
findAll() {
return [{ id: 1, name: 'John Doe' }];
}
}
@Injectable()
export class AuthService {
constructor(private usersService: UsersService) {}
validateUser(id: number) {
const users = this.usersService.findAll();
return users.find(user => user.id === id);
}
}
Injecting a Provider
To inject a provider inside its own module, say the controller, here’s how you would do it:
Declare the Provider in a Module: First, declare the provider in its module. Providers are declared in the
providers
array of the@Module()
decorator.import { Module } from '@nestjs/common'; import { UserService, AuthService } from './user.service'; @Module({ providers: [UserService, AuthService], controllers: [UserController], }) export class UsersModule {}
Inject the provider into any controller or provider by specifying it in the constructor
import { Body, Controller, Get } from '@nestjs/common'; import { UserService } from './user.service'; @Controller('users') export class UserController { constructor(private userService: UserService) {} @Get() getAllUsers() { return this.userService.findAll(); } }
In most cases you will want to access a provider in different modules. To inject a provider into another module, controller, or provider, follow these steps:
Declare the Provider in a Module (Same step 1 as above): First, declare the provider in its own module (where you want it to be available). Providers are declared in the
providers
array of the@Module()
decorator. Then export it by adding it to theexports
array.import { Module } from '@nestjs/common'; import { UsersService } from './users.service'; import { AuthService } from './auth.service'; @Module({ providers: [UsersService, AuthService], exports: [UsersService], // Exporting to make it available in other modules }) export class UsersModule {}
Import the Module: If you want to use the
UsersService
in another module, you need to import the module that provides it.import { Module } from '@nestjs/common'; import { UsersModule } from './users/users.module'; import { SomeOtherService } from './some-other.service'; @Module({ imports: [UsersModule], // Importing UsersModule to access UsersService providers: [SomeOtherService], }) export class SomeOtherModule {}
Inject the Provider into a Controller or Another Provider: Now that the provider (
UsersService
) is available, you can inject it into any controller or provider by specifying it in the constructor.If you want to use UserService in SomeOtherService, do it like this
import { Injectable } from '@nestjs/common'; import { UsersService } from './users.service'; @Injectable() export class SomeOtherService { constructor(private readonly usersService: UsersService) {} findSomeOtherService() { return this.usersService.findAll(); } }
In summary to create a provider:
Create a Provider: Define a class with the
@Injectable()
decorator.Declare the Provider in a Module: Add the provider to the
providers
array of a module.Export the Provider (if needed): If the provider needs to be used in another module, export it by adding it to the
exports
array.Import the Module (if needed): In the consuming module, import the module that exports the provider.
Inject the Provider: Inject the provider into any class (controller, service, etc.) by specifying it in the constructor.
Providers can be used to create services, factories, repositories, helper utilities; you can even create your own custom providers and inject them wherever as needed.
In conclusion, next is pretty cool
Subscribe to my newsletter
Read articles from Shalon N. Ngigi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by