<h2>Versionamento de APIs RESTful</h2>
<p>O versionamento é fundamental para manter compatibilidade com clientes enquanto evolui sua API. A estratégia mais comum é incluir a versão na URL, permitindo que diferentes versões coexistam no mesmo servidor. Com Express, implementamos isso facilmente usando middleware e roteadores separados.</p>
<pre><code class="language-javascript">const express = require('express');
const app = express();
// Router V1
const routerV1 = express.Router();
routerV1.get('/users', (req, res) => {
res.json({ version: 'v1', users: [{ id: 1, name: 'João' }] });
});
// Router V2 com estrutura diferente
const routerV2 = express.Router();
routerV2.get('/users', (req, res) => {
res.json({
version: 'v2',
data: { users: [{ id: 1, name: 'João', email: 'joao@email.com' }] },
meta: { total: 1 }
});
});
app.use('/api/v1', routerV1);
app.use('/api/v2', routerV2);
app.listen(3000);</code></pre>
<p>Este padrão permite deprecar versões antigas sem quebrar clientes existentes. Você pode adicionar middleware de aviso para versões antigas, notificando desenvolvedores sobre atualizações futuras. A chave é documentar claramente qual será o deadline para cada versão.</p>
<h2>Rate Limiting e Throttling</h2>
<p>Rate limiting protege sua API contra abuso e garante que recursos sejam distribuídos equitativamente entre clientes. O pacote <code>express-rate-limit</code> é o padrão da indústria para esta tarefa. Implementaremos diferentes limites para diferentes rotas.</p>
<pre><code class="language-javascript">const rateLimit = require('express-rate-limit');
// Limite global: 100 requisições por 15 minutos
const globalLimiter = rateLimit({
windowMs: 15 60 1000,
max: 100,
message: 'Muitas requisições deste IP, tente novamente mais tarde.',
standardHeaders: true,
legacyHeaders: false,
});
// Limite mais rigoroso para login: 5 tentativas por 15 minutos
const loginLimiter = rateLimit({
windowMs: 15 60 1000,
max: 5,
skipSuccessfulRequests: true,
keyGenerator: (req) => req.body.email || req.ip
});
// Limite suave para leitura: 1000 requisições por hora
const readLimiter = rateLimit({
windowMs: 60 60 1000,
max: 1000,
});
app.use(globalLimiter);
app.post('/login', loginLimiter, (req, res) => {
// Lógica de autenticação
res.json({ token: 'abc123' });
});
app.get('/data', readLimiter, (req, res) => {
res.json({ data: 'informações públicas' });
});</code></pre>
<p>Para produção com múltiplos servidores, use um store como Redis em vez de memória local. A biblioteca fornece <code>RedisStore</code> que sincroniza limites entre instâncias. Sempre retorne headers informativos (<code>RateLimit-Limit</code>, <code>RateLimit-Remaining</code>) para o cliente entender seu status.</p>
<h2>Cache Inteligente com Redis</h2>
<p>Cache reduz carga no servidor e melhora significativamente a latência. Implementaremos cache em camadas: algumas rotas com cache de curta duração, outras sem cache. Redis é ideal, mas também mostraremos cache em memória para desenvolvimento.</p>
<pre><code class="language-javascript">const redis = require('redis');
const client = redis.createClient();
// Middleware de cache genérico
const cacheMiddleware = (duracao = 300) => {
return async (req, res, next) => {
if (req.method !== 'GET') return next();
const chave = cache:${req.originalUrl};
try {
const dados = await client.get(chave);
if (dados) {
res.set('X-Cache', 'HIT');
return res.json(JSON.parse(dados));
}
} catch (erro) {
console.error('Erro ao acessar cache:', erro);
}
res.set('X-Cache', 'MISS');
// Intercepta res.json original
const jsonOriginal = res.json.bind(res);
res.json = (dados) => {
client.setEx(chave, duracao, JSON.stringify(dados))
.catch(erro => console.error('Erro ao salvar cache:', erro));
return jsonOriginal(dados);
};
next();
};
};
// Rotas com cache de 5 minutos
app.get('/products', cacheMiddleware(300), (req, res) => {
const produtos = [
{ id: 1, nome: 'Notebook', preco: 3000 },
{ id: 2, nome: 'Mouse', preco: 50 }
];
res.json(produtos);
});
// Rota sem cache (dados em tempo real)
app.get('/stock/:id', (req, res) => {
res.json({ stock: Math.floor(Math.random() * 100) });
});
// Invalidar cache ao atualizar
app.put('/products/:id', async (req, res) => {
// Lógica de atualização
// Invalida cache de produtos
await client.del(cache:/api/products);
res.json({ sucesso: true });
});</code></pre>
<p>A estratégia correta é cachear dados que mudam infrequentemente e invalidar seletivamente. Use headers HTTP como <code>Cache-Control: public, max-age=300</code> para que navegadores e proxies também façam cache, reduzindo requisições até sua API.</p>
<h3>### Validação de Cache</h3>
<p>Nem todos os dados devem ser cacheados. Adicione lógica condicional: dados confidenciais nunca devem entrar em cache, e endpoints que retornam diferentes dados por usuário precisam de chaves única por usuário.</p>
<pre><code class="language-javascript">const cacheSelectivo = (duracao = 300) => {
return async (req, res, next) => {
const usuario = req.user?.id;
const ehPublico = !usuario && req.path.includes('/public');
if (!ehPublico) return next();
const chave = cache:${req.originalUrl};
const dados = await client.get(chave);
if (dados) {
res.set('X-Cache', 'HIT');
return res.json(JSON.parse(dados));
}
next();
};
};</code></pre>
<h2>Conclusão</h2>
<p>Dominar <strong>versionamento</strong> permite evolução sustentável da API sem quebrar clientes. <strong>Rate limiting</strong> protege recursos e garante equidade entre usuários. <strong>Cache inteligente</strong> com Redis reduz latência e carga do servidor — mas sempre com invalidação estratégica. A combinação dessas três técnicas transforma uma API amadora em um serviço profissional, escalável e resiliente. Comece implementando em desenvolvimento, teste com carga realista e ajuste os parâmetros conforme observa o comportamento em produção.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://expressjs.com/" target="_blank" rel="noopener noreferrer">Express Official Documentation</a></li>
<li><a href="https://github.com/nfriedly/express-rate-limit" target="_blank" rel="noopener noreferrer">express-rate-limit GitHub</a></li>
<li><a href="https://redis.io/documentation" target="_blank" rel="noopener noreferrer">Redis Official Documentation</a></li>
<li><a href="https://stripe.com/blog/api-versioning" target="_blank" rel="noopener noreferrer">API Versioning Best Practices - Stripe Blog</a></li>
<li><a href="https://tools.ietf.org/html/rfc7234" target="_blank" rel="noopener noreferrer">HTTP Caching RFC 7234</a></li>
</ul>