Express.js: roteamento e middlewares
1. Introdução ao Express.js e sua arquitetura
Express.js é o framework web mais popular do ecossistema Node.js, utilizado para construir APIs e aplicações web de forma rápida e estruturada. Ele fornece uma camada minimalista sobre o módulo HTTP nativo do Node, abstraindo complexidades e oferecendo recursos poderosos como roteamento, middlewares e integração com templates.
Para começar, instale o Express em seu projeto:
npm install express
Uma aplicação mínima no Express segue esta estrutura:
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.send('Olá, mundo!');
});
app.listen(port, () => {
console.log(`Servidor rodando em http://localhost:${port}`);
});
A arquitetura do Express é baseada em um ciclo de requisição-resposta onde cada requisição passa por uma série de funções (middlewares) até chegar ao handler final da rota.
2. Roteamento básico com Express
O Express mapeia métodos HTTP para rotas específicas. Veja como definir rotas para operações CRUD:
// GET - listar usuários
app.get('/usuarios', (req, res) => {
res.json([{ id: 1, nome: 'João' }]);
});
// POST - criar usuário
app.post('/usuarios', (req, res) => {
const { nome } = req.body;
res.status(201).json({ id: 2, nome });
});
// PUT - atualizar usuário
app.put('/usuarios/:id', (req, res) => {
const { id } = req.params;
res.json({ id, nome: 'Atualizado' });
});
// DELETE - remover usuário
app.delete('/usuarios/:id', (req, res) => {
const { id } = req.params;
res.status(204).send();
});
Para acessar parâmetros de rota e query:
app.get('/produtos/:categoria/:id', (req, res) => {
const { categoria, id } = req.params; // /produtos/eletronicos/5
const { page, limit } = req.query; // ?page=1&limit=10
res.json({ categoria, id, page, limit });
});
Para modularizar as rotas, utilize express.Router():
// routes/usuarios.js
const router = express.Router();
router.get('/', (req, res) => { /* ... */ });
router.post('/', (req, res) => { /* ... */ });
module.exports = router;
// app.js
const usuariosRouter = require('./routes/usuarios');
app.use('/usuarios', usuariosRouter);
3. Roteamento avançado e boas práticas
É possível encadear múltiplos handlers em uma mesma rota, utilizando next() para passar o controle ao próximo handler:
app.get('/admin',
(req, res, next) => {
if (!req.query.token) {
return res.status(401).json({ erro: 'Token obrigatório' });
}
req.usuario = { role: 'admin' }; // enriquecendo a requisição
next();
},
(req, res) => {
res.json({ mensagem: 'Acesso autorizado', usuario: req.usuario });
}
);
Organize suas rotas em arquivos separados dentro de uma pasta routes/:
routes/
├── usuarios.js
├── produtos.js
└── auth.js
Cada arquivo exporta um router que é montado no app.js com prefixos adequados.
4. O que são middlewares no Express.js
Middlewares são funções que têm acesso ao objeto de requisição (req), ao objeto de resposta (res) e à próxima função no ciclo (next). Eles podem:
- Executar qualquer código
- Modificar os objetos
reqeres - Encerrar o ciclo (enviando uma resposta)
- Chamar o próximo middleware com
next()
Existem três tipos principais:
- Middleware de aplicação: aplicado globalmente com
app.use() - Middleware de rota: aplicado a rotas específicas
- Middleware de erro: recebe 4 parâmetros
(err, req, res, next)
Exemplo prático de middleware de logging:
const logger = (req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
next();
};
app.use(logger); // aplicado a todas as rotas
5. Middlewares embutidos e de terceiros
O Express oferece middlewares embutidos essenciais:
// Parsing de JSON no corpo da requisição
app.use(express.json());
// Parsing de dados de formulário URL-encoded
app.use(express.urlencoded({ extended: true }));
// Servir arquivos estáticos da pasta 'public'
app.use(express.static('public'));
Middlewares de terceiros populares:
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
app.use(cors()); // Habilitar CORS
app.use(helmet()); // Segurança HTTP
app.use(morgan('dev')); // Logging detalhado
6. Middlewares personalizados e cadeia de execução
Crie um middleware de autenticação simples:
const autenticar = (req, res, next) => {
const token = req.headers['authorization'];
if (!token || token !== 'meu-token-secreto') {
return res.status(401).json({ erro: 'Não autorizado' });
}
req.usuario = { id: 1, nome: 'Admin' };
next();
};
// Aplicar a uma rota específica
app.get('/perfil', autenticar, (req, res) => {
res.json({ usuario: req.usuario });
});
Middleware de validação manual:
const validarUsuario = (req, res, next) => {
const { nome, email } = req.body;
const erros = [];
if (!nome || nome.length < 3) erros.push('Nome deve ter pelo menos 3 caracteres');
if (!email || !email.includes('@')) erros.push('Email inválido');
if (erros.length > 0) {
return res.status(400).json({ erros });
}
next();
};
app.post('/usuarios', validarUsuario, (req, res) => {
res.status(201).json({ mensagem: 'Usuário criado' });
});
Para controle de fluxo com erros, use next(err):
app.get('/dados', (req, res, next) => {
try {
const dados = buscarDadosDoSistema(); // pode lançar erro
res.json(dados);
} catch (erro) {
next(erro); // passa para o middleware de erro
}
});
7. Tratamento de erros e middlewares de erro
Um middleware de erro padrão deve ter 4 parâmetros:
app.use((err, req, res, next) => {
console.error(err.stack);
const status = err.status || 500;
const mensagem = err.message || 'Erro interno do servidor';
res.status(status).json({
erro: true,
mensagem,
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
});
});
Centralize os erros criando classes personalizadas:
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
}
}
// Uso
app.get('/recurso/:id', (req, res, next) => {
const recurso = buscarPorId(req.params.id);
if (!recurso) {
return next(new AppError('Recurso não encontrado', 404));
}
res.json(recurso);
});
8. Integração com React e dicas finais
Criando uma API REST para servir dados ao React:
// backend/server.js
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({ origin: 'http://localhost:5173' }));
app.use(express.json());
// Rotas da API
app.get('/api/usuarios', (req, res) => {
res.json(usuarios);
});
app.listen(3001);
No frontend React:
// frontend/src/App.jsx
fetch('http://localhost:3001/api/usuarios')
.then(res => res.json())
.then(data => setUsuarios(data));
Boas práticas finais:
- Separação de responsabilidades: mantenha rotas, controllers e middlewares em arquivos separados
- Documentação: utilize Swagger/OpenAPI para documentar suas rotas
- Testes: escreva testes unitários e de integração usando Jest e Supertest
- Ambientes: configure diferentes ambientes (dev, homolog, prod) com variáveis de ambiente
Referências
- Documentação oficial do Express.js - Roteamento — Guia completo sobre roteamento, parâmetros de rota e express.Router()
- Documentação oficial do Express.js - Middlewares — Explicação detalhada sobre middlewares de aplicação, rota e erro
- MDN Web Docs - Express/Node introduction — Introdução ao Express no ecossistema Node.js pela Mozilla
- DigitalOcean - How To Create a Web Server in Node.js with Express — Tutorial prático criando um servidor web completo com Express
- freeCodeCamp - Express.js Tutorial: Build a REST API — Tutorial completo construindo uma API REST com Express, incluindo middlewares e tratamento de erros
- Rocketseat - Guia completo de Express.js — Artigo em português abordando desde conceitos básicos até middlewares avançados