<h2>Express.js: Fundamentos e Arquitetura</h2>
<p>Express.js é um framework web minimalista para Node.js que facilita a criação de servidores HTTP e APIs REST. Sua força reside na simplicidade: você constrói apenas o que precisa, sem abstrações desnecessárias. O framework é construído sobre o módulo nativo <code>http</code> do Node.js, adicionando camadas de roteamento, middleware e utilitários que aceleram o desenvolvimento.</p>
<p>Para começar, instale Express via npm: <code>npm install express</code>. Um servidor básico requer apenas alguns comandos para escutar requisições. A arquitetura do Express é orientada por middlewares — funções que processam requisições antes de chegarem à rota final. Compreender esse fluxo é essencial para dominar o framework.</p>
<pre><code class="language-javascript">const express = require('express');
const app = express();
app.listen(3000, () => {
console.log('Servidor rodando na porta 3000');
});</code></pre>
<h2>Roteamento: O Coração das APIs</h2>
<h3>Definindo Rotas Básicas</h3>
<p>Rotas definem como sua API responde a diferentes URLs e métodos HTTP. Express fornece métodos diretos para GET, POST, PUT, DELETE e outros. Cada rota é composta por um caminho, um método HTTP e uma função callback que recebe <code>request</code> e <code>response</code>.</p>
<pre><code class="language-javascript">const express = require('express');
const app = express();
// GET
app.get('/usuarios', (req, res) => {
res.json({ message: 'Lista de usuários' });
});
// POST
app.post('/usuarios', (req, res) => {
res.status(201).json({ message: 'Usuário criado' });
});
// PUT
app.put('/usuarios/:id', (req, res) => {
res.json({ message: Usuário ${req.params.id} atualizado });
});
// DELETE
app.delete('/usuarios/:id', (req, res) => {
res.status(204).send();
});
app.listen(3000);</code></pre>
<h3>Parâmetros e Query Strings</h3>
<p>Existem três formas principais de capturar dados: parâmetros de rota (<code>req.params</code>), query strings (<code>req.query</code>) e body (<code>req.body</code>). Parâmetros de rota são valores obrigatórios na URL; query strings são opcionais e vêm após <code>?</code>. O body contém dados estruturados enviados em POST/PUT.</p>
<pre><code class="language-javascript">// Parâmetro de rota: /produtos/123
app.get('/produtos/:id', (req, res) => {
console.log(req.params.id); // "123"
res.json({ id: req.params.id });
});
// Query string: /produtos?categoria=eletrônicos&preco=100
app.get('/produtos', (req, res) => {
console.log(req.query.categoria); // "eletrônicos"
console.log(req.query.preco); // "100"
res.json({ categoria: req.query.categoria });
});
// Body (requer middleware express.json())
app.post('/produtos', (req, res) => {
console.log(req.body.nome); // dados do formulário
res.json({ received: req.body });
});</code></pre>
<h2>Middlewares: Processamento em Cadeia</h2>
<p>Middlewares são funções executadas entre a requisição e a resposta. Cada middleware pode modificar <code>req</code> e <code>res</code>, passar o controle para o próximo middleware via <code>next()</code> ou encerrar a requisição com uma resposta. Essa arquitetura permite separar responsabilidades como autenticação, validação e logging.</p>
<pre><code class="language-javascript">const express = require('express');
const app = express();
// Middleware global
app.use(express.json()); // Parse JSON automaticamente
// Middleware customizado de logging
app.use((req, res, next) => {
console.log(${new Date().toISOString()} - ${req.method} ${req.path});
next(); // Passa para o próximo middleware
});
// Middleware de autenticação
const verificarToken = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ erro: 'Token ausente' });
}
req.usuario = { id: 1, nome: 'João' }; // Simulado
next();
};
// Usando middleware em rota específica
app.get('/dados-privados', verificarToken, (req, res) => {
res.json({ mensagem: Olá, ${req.usuario.nome} });
});
// Middleware de erro (deve ser o último)
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ erro: 'Erro interno do servidor' });
});
app.listen(3000);</code></pre>
<h2>Estrutura de APIs REST Profissional</h2>
<h3>Organização em Camadas</h3>
<p>Uma API REST profissional separava responsabilidades em camadas: rotas, controllers e models. As rotas apenas mapeiam URLs para funções; controllers contêm a lógica de negócio; models representam dados. Essa estrutura facilita testes, manutenção e escalabilidade.</p>
<pre><code class="language-javascript">// routes/usuarios.js
const express = require('express');
const router = express.Router();
const usuariosController = require('../controllers/usuariosController');
router.get('/', usuariosController.listar);
router.post('/', usuariosController.criar);
router.get('/:id', usuariosController.obter);
router.put('/:id', usuariosController.atualizar);
router.delete('/:id', usuariosController.deletar);
module.exports = router;
// controllers/usuariosController.js
const usuarios = []; // Simulado
exports.listar = (req, res) => {
res.json(usuarios);
};
exports.criar = (req, res) => {
const novoUsuario = { id: Date.now(), ...req.body };
usuarios.push(novoUsuario);
res.status(201).json(novoUsuario);
};
exports.obter = (req, res) => {
const usuario = usuarios.find(u => u.id == req.params.id);
if (!usuario) return res.status(404).json({ erro: 'Não encontrado' });
res.json(usuario);
};
exports.atualizar = (req, res) => {
const usuario = usuarios.find(u => u.id == req.params.id);
if (!usuario) return res.status(404).json({ erro: 'Não encontrado' });
Object.assign(usuario, req.body);
res.json(usuario);
};
exports.deletar = (req, res) => {
const index = usuarios.findIndex(u => u.id == req.params.id);
if (index === -1) return res.status(404).json({ erro: 'Não encontrado' });
usuarios.splice(index, 1);
res.status(204).send();
};
// app.js
const express = require('express');
const usuariosRouter = require('./routes/usuarios');
const app = express();
app.use(express.json());
app.use('/api/usuarios', usuariosRouter);
app.listen(3000);</code></pre>
<h3>Tratamento de Erros e Validação</h3>
<p>Toda API robusta precisa validar dados recebidos e comunicar erros claramente. Use bibliotecas como <code>joi</code> ou <code>express-validator</code> para validação declarativa. Sempre retorne status HTTP apropriados: 400 para dados inválidos, 404 para não encontrado, 500 para erro do servidor.</p>
<pre><code class="language-javascript">const { body, validationResult } = require('express-validator');
app.post('/usuarios',
body('email').isEmail(),
body('idade').isInt({ min: 18 }),
(req, res) => {
const erros = validationResult(req);
if (!erros.isEmpty()) {
return res.status(400).json({ erros: erros.array() });
}
// Lógica de criação
res.status(201).json({ success: true });
}
);</code></pre>
<h2>Conclusão</h2>
<p>Os três pilares do Express.js — <strong>roteamento bem organizado</strong>, <strong>middlewares para separar responsabilidades</strong> e <strong>estrutura em camadas</strong> — formam a base de qualquer API REST profissional. Domine o fluxo de requisição-resposta, use middlewares para código limpo e escalável, e organize suas rotas e controllers de forma lógica. Esses fundamentos aplicados transformam um projeto caótico em uma aplicação mantível e testável.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://expressjs.com/" target="_blank" rel="noopener noreferrer">Documentação Oficial Express.js</a></li>
<li><a href="https://github.com/goldbergyoni/nodebestpractices" target="_blank" rel="noopener noreferrer">Node.js Best Practices</a></li>
<li><a href="https://restfulapi.net/" target="_blank" rel="noopener noreferrer">RESTful API Design Guidelines</a></li>
<li><a href="https://expressjs.com/en/guide/using-middleware.html" target="_blank" rel="noopener noreferrer">Express Middleware Guide</a></li>
<li><a href="https://express-validator.github.io/docs/" target="_blank" rel="noopener noreferrer">Express-Validator Documentation</a></li>
</ul>