Trong NestJS – một framework cực kỳ mạnh mẽ và có cấu trúc rõ ràng cho Node.js – khái niệm Dependency Injection (DI) là linh hồn của mọi module. Và để thực hiện DI, NestJS cung cấp một loạt các Inject Decorators giúp bạn dễ dàng khai báo, cấu hình và sử dụng các service một cách tường minh.
Bài viết này sẽ hướng dẫn bạn từ A-Z các loại inject decorators thường gặp, kèm ví dụ cụ thể, giúp bạn áp dụng được ngay vào dự án thực tế.
- @Injectable(): Khai báo Service có thể Inject
Decorator này giúp đánh dấu một class có thể được NestJS quản lý và inject vào nơi khác (controller, service khác, v.v.).
Ví dụ
@Injectable()
export class UsersService {
findAll() {
return ['user1', 'user2'];
}
}
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
getUsers() {
return this.usersService.findAll();
}
}
Rất đơn giản phải không, chúng ta sẽ thường xuyên thấy và áp dụng khi implement các service class hoặc bất cứ class này bạn muốn nó được inject vào class khác.
2. @Inject(token): Inject theo Token thủ công
Loại decotor inject này có chức năng khi bạn dùng useClass, useValue, useFactory, hoặc inject các provider có tên (token), bạn cần dùng @Inject() để chỉ định.
Ví dụ
// trong module
{
provide: 'CONFIG',
useValue: { debug: true }
}
// trong constructor
constructor(@Inject('CONFIG') private config: { debug: boolean }) {
console.log(config.debug);
}
Bảng so sánh sự khác nhau chính giữa @Injectable() và @Inject()
Tiêu chí |
@Injectable() |
@Inject() |
---|---|---|
Mục đích chính |
Đánh dấu một class là có thể được NestJS quản lý (inject được vào nơi khác) |
Dùng để chỉ định cụ thể token khi inject vào constructor |
Dùng ở đâu |
Trên class (service, provider) |
Trong constructor (trước một parameter) |
Khi nào cần |
Luôn cần khi bạn tạo service riêng |
Chỉ cần khi inject bằng custom token hoặc dùng useValue, useClass, useFactory |
Ví dụ điển hình |
@Injectable() export class MyService {} |
constructor(@Inject('MY_TOKEN') private config: Config) {} |
Có tạo instance không? |
Có – Nest sẽ tự khởi tạo instance nếu module import đúng |
Không – chỉ dùng để lấy instance đã được khai báo trước đó bằng token |
3. @Optional(): Không có cũng được
Inject này giúp đánh dấu dependency là tùy chọn. Nếu không có, sẽ không throw error mà chỉ trả về undefined.
Ví dụ
constructor(@Optional() private readonly logger?: LoggerService) {
logger?.log('Logger exists!');
}
4. @Inject(forwardRef(() => ...)): Giải quyết vòng lặp dependency
Khi 2 service phụ thuộc lẫn nhau (circular dependency), bạn phải dùng forwardRef để trì hoãn việc inject cho đến khi cả 2 được định nghĩa đầy đủ.
Ví dụ
// trong CatsService
constructor(
@Inject(forwardRef(() => DogsService))
private readonly dogsService: DogsService,
) {}
// trong DogsService
constructor(
@Inject(forwardRef(() => CatsService))
private readonly catsService: CatsService,
) {}
5. @Global()(Module decorator – liên quan inject)
Đánh dấu một module là toàn cục (global) – các provider bên trong có thể được inject ở bất kỳ đâu mà không cần import lại module đó.
Ví dụ
@Global()
@Module({
providers: [ConfigService],
exports: [ConfigService],
})
export class ConfigModule {}
6. Các Inject Decorator từ thư viện ngoài
Decorator |
Thư viện |
Mục đích |
---|---|---|
@InjectRepository() |
@nestjs/typeorm |
Inject repository TypeORM |
@InjectModel() |
@nestjs/mongoose |
Inject model Mongoose |
@InjectQueue() |
@nestjs/bull |
Inject Bull Queue |
@InjectConnection() |
@nestjs/mongoose |
Inject MongoDB connection |
Dependency Injection là trái tim của NestJS – giúp tách biệt các phần logic và dễ kiểm thử. Nắm vững các inject decorator sẽ giúp bạn xây dựng ứng dụng dễ mở rộng, bảo trì tốt, và chuyên nghiệp hơn.
BÌNH LUẬN
Địa chỉ email của bạn sẽ không được công khai.