Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
40 prioritized NestJS best practices across architecture, DI, security, performance, testing, and microservices.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
rules/di-avoid-service-locator.md
1---2title: Avoid Service Locator Anti-Pattern3impact: HIGH4impactDescription: Hides dependencies and breaks testability5tags: dependency-injection, anti-patterns, testing6---78## Avoid Service Locator Anti-Pattern910Avoid using `ModuleRef.get()` or global containers to resolve dependencies at runtime. This hides dependencies, makes code harder to test, and breaks the benefits of dependency injection. Use constructor injection instead.1112**Incorrect (service locator anti-pattern):**1314```typescript15// Use ModuleRef to get dependencies dynamically16@Injectable()17export class OrdersService {18constructor(private moduleRef: ModuleRef) {}1920async createOrder(dto: CreateOrderDto): Promise<Order> {21// Dependencies are hidden - not visible in constructor22const usersService = this.moduleRef.get(UsersService);23const inventoryService = this.moduleRef.get(InventoryService);24const paymentService = this.moduleRef.get(PaymentService);2526const user = await usersService.findOne(dto.userId);27// ... rest of logic28}29}3031// Global singleton container32class ServiceContainer {33private static instance: ServiceContainer;34private services = new Map<string, any>();3536static getInstance(): ServiceContainer {37if (!this.instance) {38this.instance = new ServiceContainer();39}40return this.instance;41}4243get<T>(key: string): T {44return this.services.get(key);45}46}47```4849**Correct (constructor injection with explicit dependencies):**5051```typescript52// Use constructor injection - dependencies are explicit53@Injectable()54export class OrdersService {55constructor(56private usersService: UsersService,57private inventoryService: InventoryService,58private paymentService: PaymentService,59) {}6061async createOrder(dto: CreateOrderDto): Promise<Order> {62const user = await this.usersService.findOne(dto.userId);63const inventory = await this.inventoryService.check(dto.items);64// Dependencies are clear and testable65}66}6768// Easy to test with mocks69describe('OrdersService', () => {70let service: OrdersService;7172beforeEach(async () => {73const module = await Test.createTestingModule({74providers: [75OrdersService,76{ provide: UsersService, useValue: mockUsersService },77{ provide: InventoryService, useValue: mockInventoryService },78{ provide: PaymentService, useValue: mockPaymentService },79],80}).compile();8182service = module.get(OrdersService);83});84});8586// VALID: Factory pattern for dynamic instantiation87@Injectable()88export class HandlerFactory {89constructor(private moduleRef: ModuleRef) {}9091getHandler(type: string): Handler {92switch (type) {93case 'email':94return this.moduleRef.get(EmailHandler);95case 'sms':96return this.moduleRef.get(SmsHandler);97default:98return this.moduleRef.get(DefaultHandler);99}100}101}102```103104Reference: [NestJS Module Reference](https://docs.nestjs.com/fundamentals/module-ref)105