<h2>Arquitetura Modular no NestJS</h2>
<p>O NestJS foi construído com a modularidade como pilar fundamental. A arquitetura modular permite organizar sua aplicação em componentes independentes e reutilizáveis, facilitando manutenção e escalabilidade. Cada módulo encapsula controladores, serviços e configurações relacionadas a um domínio específico da aplicação.</p>
<p>Para criar um módulo, você precisa de um arquivo de definição que use o decorator <code>@Module()</code>. Vamos construir um exemplo prático com um módulo de usuários:</p>
<pre><code class="language-typescript">// users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@Module({
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService], // Permite outros módulos usarem este serviço
})
export class UsersModule {}</code></pre>
<p>O módulo acima exporta <code>UsersService</code>, permitindo que outros módulos o importem. No <code>app.module.ts</code> principal, você importa os módulos:</p>
<pre><code class="language-typescript">// app.module.ts
import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';
import { AuthModule } from './auth/auth.module';
@Module({
imports: [UsersModule, AuthModule],
})
export class AppModule {}</code></pre>
<p>Essa estrutura garante baixo acoplamento e alta coesão — princípios fundamentais de bom design.</p>
<h2>Injeção de Dependência (DI) e Provedores</h2>
<p>A Injeção de Dependência no NestJS é gerenciada automaticamente pelo container IoC (Inversão de Controle). Provedores são classes marcadas com <code>@Injectable()</code> que podem ser injetadas em controladores, outros serviços ou guards. Isso elimina a necessidade de instanciação manual e facilita testes.</p>
<p>Vejamos um exemplo completo com um serviço que usa banco de dados:</p>
<pre><code class="language-typescript">// users.service.ts
import { Injectable } from '@nestjs/common';
interface User {
id: number;
name: string;
email: string;
}
@Injectable()
export class UsersService {
private users: User[] = [
{ id: 1, name: 'João', email: 'joao@example.com' },
{ id: 2, name: 'Maria', email: 'maria@example.com' },
];
findAll(): User[] {
return this.users;
}
findById(id: number): User | undefined {
return this.users.find(user => user.id === id);
}
create(name: string, email: string): User {
const newUser: User = {
id: this.users.length + 1,
name,
email,
};
this.users.push(newUser);
return newUser;
}
}</code></pre>
<p>Agora o controlador injeta o serviço:</p>
<pre><code class="language-typescript">// users.controller.ts
import { Controller, Get, Post, Param, Body } from '@nestjs/common';
import { UsersService } from './users.service';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll() {
return this.usersService.findAll();
}
@Get(':id')
findById(@Param('id') id: string) {
return this.usersService.findById(parseInt(id));
}
@Post()
create(@Body() body: { name: string; email: string }) {
return this.usersService.create(body.name, body.email);
}
}</code></pre>
<p>O NestJS automaticamente instancia <code>UsersService</code> e a injeta no controlador. Para injetar em outro serviço, use a mesma sintaxe.</p>
<h3>Provedores Customizados</h3>
<p>Às vezes você precisa configurar provedores de forma mais complexa. Use o padrão de objeto:</p>
<pre><code class="language-typescript">// users.module.ts (atualizado)
@Module({
providers: [
{
provide: 'USER_REPOSITORY',
useValue: [], // Valor direto
},
UsersService,
],
})
export class UsersModule {}</code></pre>
<p>E injete com <code>@Inject()</code>:</p>
<pre><code class="language-typescript">constructor(@Inject('USER_REPOSITORY') private userRepo: any[]) {}</code></pre>
<h2>Guards e Autenticação</h2>
<p>Guards são responsáveis por controlar o acesso às rotas. Eles implementam a interface <code>CanActivate</code> e retornam <code>true</code> para permitir acesso ou <code>false</code> para bloqueá-lo. Um caso de uso comum é validar tokens JWT.</p>
<p>Vamos criar um guard de autenticação:</p>
<pre><code class="language-typescript">// auth.guard.ts
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { Request } from 'express';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest<Request>();
const token = request.headers.authorization?.split(' ')[1];
if (!token) {
throw new UnauthorizedException('Token não encontrado');
}
// Validação simplificada — em produção use JWT real
if (token !== 'valid-token-123') {
throw new UnauthorizedException('Token inválido');
}
request['user'] = { id: 1, name: 'João' }; // Adiciona usuário à requisição
return true;
}
}</code></pre>
<p>Agora use o guard nas rotas:</p>
<pre><code class="language-typescript">// users.controller.ts (atualizado)
import { UseGuards } from '@nestjs/common';
import { AuthGuard } from '../auth/auth.guard';
@Controller('users')
@UseGuards(AuthGuard) // Aplica globalmente ao controlador
export class UsersController {
// ... métodos anteriores
}</code></pre>
<p>Ou aplique apenas em métodos específicos:</p>
<pre><code class="language-typescript">@Get('profile')
@UseGuards(AuthGuard)
getProfile(@Request() req: any) {
return req.user;
}</code></pre>
<p>Para aplicar globalmente a toda aplicação, configure no <code>main.ts</code>:</p>
<pre><code class="language-typescript">// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AuthGuard } from './auth/auth.guard';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalGuards(new AuthGuard());
await app.listen(3000);
}
bootstrap();</code></pre>
<h3>Guards com Roles</h3>
<p>Para controle baseado em papéis, crie um guard que verifica permissões:</p>
<pre><code class="language-typescript">// roles.guard.ts
import { Injectable, CanActivate, ExecutionContext, ForbiddenException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.get<string[]>('roles', context.getHandler());
if (!requiredRoles) {
return true; // Sem restrição se não houver roles definidas
}
const request = context.switchToHttp().getRequest();
const userRole = request.user?.role;
if (!requiredRoles.includes(userRole)) {
throw new ForbiddenException('Acesso negado');
}
return true;
}
}</code></pre>
<p>Use com um decorator customizado:</p>
<pre><code class="language-typescript">// roles.decorator.ts
import { SetMetadata } from '@nestjs/common';
export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
// Na rota:
@Get('admin')
@Roles('admin')
@UseGuards(RolesGuard)
getAdminData() {
return { message: 'Dados sensíveis' };
}</code></pre>
<h2>Conclusão</h2>
<p>Dominando esses três pilares — <strong>arquitetura modular</strong>, <strong>injeção de dependência</strong> e <strong>guards</strong> — você construirá aplicações NestJS profissionais, testáveis e seguras. A modularidade permite organização escalável, a DI reduz acoplamento e facilita testes, enquanto guards protegem suas rotas com lógica de autenticação e autorização robusta. Pratique combinando esses conceitos em projetos reais para consolidar o aprendizado.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://docs.nestjs.com/" target="_blank" rel="noopener noreferrer">NestJS Official Documentation</a></li>
<li><a href="https://docs.nestjs.com/modules" target="_blank" rel="noopener noreferrer">NestJS Modules Guide</a></li>
<li><a href="https://docs.nestjs.com/guards" target="_blank" rel="noopener noreferrer">NestJS Guards Documentation</a></li>
<li><a href="https://www.typescriptlang.org/docs/" target="_blank" rel="noopener noreferrer">TypeScript Handbook</a></li>
<li><a href="https://docs.nestjs.com/techniques/validation" target="_blank" rel="noopener noreferrer">NestJS Best Practices</a></li>
</ul>