Injeção de Dependência
Use o contêiner de DI do NestJS 11 para escopos, provedores customizados e orquestração de serviços testáveis.
Receita
Cartão de receita de referência rápida - pronto para copiar e colar.
import { Module, Injectable, Inject } from "@nestjs/common";
@Injectable()
export class UsersRepository {
findById(id: string) { return { id, name: "Ada" }; }
}
@Injectable()
export class UsersService {
constructor(private readonly repo: UsersRepository) {}
getUser(id: string) {
return this.repo.findById(id);
}
}
@Module({
providers: [UsersRepository, UsersService],
exports: [UsersService],
})
export class UsersModule {}Quando usar isso: Qualquer serviço NestJS que dependa de outro serviço, repositório ou cliente externo.
Exemplo de Trabalho
import { Module, Injectable, Inject } from "@nestjs/common";
import { Test } from "@nestjs/testing";
// Token de interface para implementações substituíveis
export const EMAIL_SENDER = Symbol("EMAIL_SENDER");
export interface EmailSender {
send(to: string, subject: string): Promise<void>;
}
@Injectable()
export class SmtpEmailSender implements EmailSender {
async send(to: string, subject: string) {
console.log(`Enviando para ${to}: ${subject}`);
}
}
@Injectable()
export class UsersService {
constructor(
@Inject(EMAIL_SENDER) private readonly email: EmailSender,
) {}
async register(email: string) {
await this.email.send(email, "Bem-vindo!");
return { email };
}
}
@Module({
providers: [
UsersService,
{ provide: EMAIL_SENDER, useClass: SmtpEmailSender },
],
})
export class UsersModule {}
// Substituição para teste
const testModule = await Test.createTestingModule({
imports: [UsersModule],
})
.overrideProvider(EMAIL_SENDER)
.useValue({ send: async () => {} })
.compile();O que isso demonstra:
- Injeção de construtor de serviços
- Tokens de provedor customizados com
Symbol useClasspara vinculação de interface a implementaçãooverrideProviderpara duplos de teste
Mergulho Profundo
Como Funciona
- O NestJS cria um contêiner de DI na inicialização.
@Injectable()registra uma classe como provedora.- Os tipos dos parâmetros do construtor determinam o que injetar.
- O contêiner resolve o grafo de dependência antes de atender às requisições.
Escopos de Provedor
| Escopo | Tempo de Vida | Usar para |
|---|---|---|
DEFAULT (singleton) | Uma instância por aplicativo | Serviços, repositórios |
REQUEST | Um por requisição HTTP | Contexto do usuário no escopo da requisição |
TRANSIENT | Nova instância por injeção | Auxiliares sem estado (raro) |
@Injectable({ scope: Scope.REQUEST })
export class RequestContextService {
userId?: string;
}Padrões de Provedor Customizado
| Padrão | Sintaxe | Usar para |
|---|---|---|
useClass | { provide: TOKEN, useClass: Impl } | Vinculação de interface |
useValue | { provide: TOKEN, useValue: obj } | Configuração, mocks |
useFactory | { provide: TOKEN, useFactory: fn, inject: [...] } | Configuração assíncrona |
useExisting | { provide: TOKEN, useExisting: OtherToken } | Criação de alias |
Armadilhas
- Dependências circulares - A injeta B, que injeta A. Correção:
forwardRef(() => B)ou refatorar a lógica compartilhada para um terceiro serviço. - Escopo de requisição em singleton - Injetar um serviço de requisição em um singleton falha. Correção: usar
ModuleRefou tornar o consumidor também com escopo de requisição. - Esquecer
exports- Serviço não disponível no módulo importador. Correção: adicionar ao arrayexports. new Service()manual - Ignora a DI e a testabilidade. Correção: sempre injetar via construtor.- Muitos provedores em um módulo - Antipadrão de módulo "god". Correção: dividir em módulos de funcionalidade.
- Não substituir em testes - Testes atingem o banco de dados real. Correção:
overrideProviderou mockuseValue.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| DI Manual (parâmetros de construtor) | App Fastify/Express simples | Projeto NestJS (usar DI embutida) |
| tsyringe | DI sem o framework NestJS | Já está no NestJS |
| Funções de fábrica | Serviços leves | Grafos de dependência complexos |
| ModuleRef.get() | Resolução dinâmica de provedor | A injeção normal via construtor funciona |
FAQs
Como eu injeto o ConfigService?
Importe ConfigModule.forRoot({ isGlobal: true }) e injete ConfigService em qualquer provedor.
Posso injetar dados da requisição em um serviço?
Use @Inject(REQUEST) com um provedor de escopo de requisição, ou passe os dados do controller para o método do serviço (mais simples).
Como compartilho um provedor entre módulos?
Adicione-o a providers e exports no módulo provedor. Importe esse módulo onde for necessário.
O que é forwardRef?
Atrasar a resolução de uma dependência circular. Use com moderação; refatorar geralmente é melhor.
Como eu injeto uma conexão de banco de dados?
useFactory com limpeza onModuleDestroy, ou use o wrapper @nestjs/typeorm / PrismaService.
A DI adiciona sobrecarga de performance?
Mínima em tempo de execução (resolução de singleton uma vez). O escopo de requisição adiciona custo de instanciação por requisição.
Como eu testo um controller com um serviço mockado?
Test.createTestingModule({ controllers: [X], providers: [{ provide: Y, useValue: mock }] }).compile().
Posso usar DI sem decoradores?
Não idiomaticamente no NestJS. Decoradores são o mecanismo principal do framework.
Relacionados
- Noções Básicas de NestJS - estrutura de módulos
- Guards, Interceptors e Pipes - aspectos transversais injetáveis
- NestJS + Prisma/TypeORM - DI na camada de dados
- Padrões de Injeção de Dependência - DI agnóstica ao framework
- Melhores Práticas de NestJS - checklist da seção
Versões da Stack: Esta página foi escrita para Node.js 24.18.0 (LTS Ativo), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 e NestJS 11.