Estágio 02 · 02-08
Lockedhttp puro de Node é spartano. Você manualmente parseia URL, body, multipart, escreve roteamento, lida com errors. Em produção real, frameworks tomam conta dessa fundação. Mas há diferença real entre eles: throughput, ergonomia, modelo de plugins, type safety, edge-readiness, ecosystem. Escolher errado é dor cara, refactor de framework em projeto vivo é trabalho de meses.
Este módulo dissecca os principais. Não é "qual é o melhor". É: como cada um foi desenhado, que problema ele optou por resolver, que problema ele empurrou pra você, e como escolher conforme o contexto.
Em essência, todos resolvem:
Diferenças nascem em: ergonomia, performance, schema validation, tipagem fim-a-fim, runtime targets (Node, Edge, Bun, Deno).
Lançado em 2010. Mais antigo, mais usado, mais ecosystem. Modelo:
import express from 'express';
const app = express();
app.use(express.json());
app.get('/orders/:id', async (req, res) => {
const order = await findById(req.params.id);
res.json(order);
});
app.listen(3000);
Pontos:
app.use, (req, res, next) => {}).next(err). Express 5 (estável agora) trata async automaticamente.passport, helmet, cors, morgan, etc.Quando vence: time já sabe; projeto pequeno-médio; cargas baixas-médias; integrar com plugin específico que só Express tem.
Lançado em 2017, foco em performance e schema validation:
import Fastify from 'fastify';
const fastify = Fastify({ logger: true });
fastify.get('/orders/:id', {
schema: {
params: { type: 'object', properties: { id: { type: 'string' } } },
response: {
200: { type: 'object', properties: { id: { type: 'string' }, total: { type: 'number' } } }
}
}
}, async (req) => findById(req.params.id));
await fastify.listen({ port: 3000 });
Pontos:
JSON.stringify).onRequest, preParsing, preValidation, preHandler, onSend, onResponse, onError.pino) por default.Quando vence: você quer performance e estrutura disciplinada; precisa validar schemas; vai escalar pra time grande.
Lançado em 2022. Framework moderno desenhado pra rodar em qualquer runtime: Node, Bun, Deno, Cloudflare Workers, Vercel Edge, AWS Lambda. Web Standard APIs (Request, Response, fetch).
import { Hono } from 'hono';
const app = new Hono();
app.get('/orders/:id', async (c) => {
const id = c.req.param('id');
const order = await findById(id);
return c.json(order);
});
export default app; // funciona em Workers, Bun, Deno
// adapter pra Node:
import { serve } from '@hono/node-server';
serve(app);
Pontos:
Request/Response nativos.@hono/zod-validator pra schema validation.@hono/zod-openapi pra OpenAPI auto.Quando vence: edge/multi-runtime, microservices serverless, projetos modernos onde você quer não estar preso a Node.
Lançado em 2017, inspirado em Angular. Framework opinado, full-featured.
@Controller('orders')
export class OrdersController {
constructor(private readonly service: OrdersService) {}
@Get(':id')
async findOne(@Param('id') id: string) {
return this.service.findOne(id);
}
}
Pontos:
Quando vence: empresa grande, time grande, time vindo de Java/.NET/C#, app complexo (microservices, GraphQL, WebSocket gateways) onde estrutura forte vale mais que leveza.
Lançado em 2023, primeiro feito pra Bun. Foca em DX e tipagem fim-a-fim:
import { Elysia, t } from 'elysia';
new Elysia()
.get('/orders/:id', ({ params }) => findById(params.id), {
params: t.Object({ id: t.String() })
})
.listen(3000);
Pontos:
Quando vence: projetos novos em Bun com foco em DX e tipagem.
Não são "frameworks HTTP" tradicionais, são camadas:
tRPC: RPC type-safe entre TS client e TS server. Você define procedures no server, client tem tipos automáticos. Roda sobre Express, Fastify, Next, Hono.
GraphQL: schema separado, query language. Apollo, Yoga, Mercurius (Fastify-based).
Decisão entre REST, tRPC, GraphQL:
Pipeline. Cada middleware recebe (req, res, next) (Express) ou retorna funções com next (Koa/Hono). Pode:
Comum a todos:
Padrão emergente: definir schema (zod/valibot/TypeBox), validar em entrada, derivar TS types e OpenAPI. Single source of truth.
OpenAPI/Swagger é a spec pra documentar APIs REST. Geração automática a partir do código:
@fastify/swagger lê schemas e gera spec.@hono/zod-openapi.@nestjs/swagger baseado em decorators e DTOs.swagger-jsdoc ou tsoa (TS Annotation, controller-first).Sem OpenAPI, integração externa vira documentação manual desatualizada. Sempre gere.
Padrão: structured logs (JSON) com:
Logs vão pra stdout. Coletor (Loki, CloudWatch, Datadog) recolhe.
Erros devem virar respostas HTTP previsíveis:
Erros específicos do domínio: subclasses de Error com code, status, details. Middleware central traduz pra response. Evite expor stacks em prod.
Problem Details (RFC 9457) é formato padronizado pra error responses. Considere.
Lib: express-rate-limit, @fastify/rate-limit, hono-rate-limiter, ou Redis-based pra distribuído.
Algoritmos:
Em backend distribuído (múltiplas instâncias), você precisa store compartilhado (Redis). Em single instance, in-memory basta. CDN/proxy pode aplicar antes de chegar (Cloudflare, AWS WAF).
Content-Encoding: gzip ou br (Brotli). Lib: compression (Express), @fastify/compress, etc.
Cache headers:
Cache-Control: public, max-age=3600ETag + If-None-Match → 304Last-Modified + If-Modified-Since → 304Vary pra negociação (Accept-Language, Accept-Encoding).Em backend de API frequentemente você faz Cache-Control: private, no-store ou tags específicas. CDN ainda pode cachear se você marca explicitamente.
Cross-Origin Resource Sharing. Browser bloqueia por default; server precisa explicitar Access-Control-Allow-Origin, -Methods, -Headers, etc.
Cuidado com:
Access-Control-Allow-Origin: * + credentials → bloqueado pelo browser. Pra credentials você lista origin explícita.OPTIONS) pra requests não-simple.Logística é multi-tenant (lojistas, entregadores, clientes). Padrões:
acme.api.example.com → middleware identifica tenant.X-Tenant-Id: acme./t/acme/orders.Onde tenant fica no contexto: AsyncLocalStorage, ou objeto de request anotado.
Nginx, Caddy, Traefik, Cloudflare na frente. Backend recebe X-Forwarded-For, X-Forwarded-Proto, etc. Frameworks têm trust proxy setting, habilite quando atrás de proxy.
req.ip real só é confiável se trust proxy estiver configurado e proxy injetar headers.
Você precisa, sem consultar:
Reescrever Logística API sobre framework, duas implementações paralelas: Fastify e Hono. Comparar.
POST /auth/login → JWT mockado.GET /orders lista paginada (auth obrigatória).POST /orders cria pedido (auth + validation).GET /orders/:id detalhe.POST /orders/:id/events registra evento.GET /orders/export.csv streaming.GET /healthz, GET /metrics.X-Tenant-Id.customerName obrigatório, total > 0, items array não vazio./docs em ambos.OrderNotFound, OrderAlreadyDelivered) viram 404/409 com Problem Details.requestId, tenantId, method, path, status, latency_ms.console.log em código de produção.server-fastify/, server-hono/).autocannon em ambos. Reportar:
GET /orders./docs).http. Hooks e plugins refletem fases do processamento que vimos.Destrava
02-08 é prereq dos seguintes módulos: