Dominando Middlewares

Express.js: Dominando Middlewares

Uma aula completa sobre o coração do Express, com conceitos e exemplos práticos.

Dominando Middlewares

1. O Conceito Fundamental: O que é um Middleware?

Pense em uma linha de montagem em uma fábrica. Antes do produto final ficar pronto, ele passa por diversas estações, onde cada uma adiciona ou modifica algo.

No Express, os Middlewares são essas estações.

São funções que têm acesso ao objeto de requisição (req), ao objeto de resposta (res) e à próxima função de middleware no ciclo de requisição-resposta da aplicação, comumente denotada por uma variável chamada next.

Dominando Middlewares

O que um Middleware pode fazer?

  • Executar qualquer código.
  • Fazer alterações nos objetos de requisição (req) e resposta (res).
  • Encerrar o ciclo de requisição-resposta (enviando uma resposta ao cliente).
  • Chamar o próximo middleware na pilha.

A regra de ouro: Se um middleware não encerra o ciclo, ele DEVE chamar next() para passar o controle para o próximo middleware. Caso contrário, a requisição ficará "pendurada" e o cliente receberá um timeout.

Dominando Middlewares

2. O Ciclo de Requisição-Resposta (Request-Response Cycle)

Quando seu servidor Express recebe uma requisição, ela passa por uma série de middlewares que você definiu, um após o outro, como um "encanamento" ou uma "pilha" (stack).


Requisição do Cliente -> [Middleware 1] -> [Middleware 2] -> [Middleware 3] -> Manipulador de Rota -> Resposta para o Cliente

Cada middleware tem a chance de "inspecionar", "modificar" ou "agir" sobre a requisição antes que ela chegue ao seu destino final (o manipulador da rota).

Dominando Middlewares

3. A Anatomia de um Middleware

A assinatura de uma função de middleware é simples e poderosa:

Dominando Middlewares
function meuMiddleware(req, res, next) {
  // Lógica do middleware aqui
  console.log('Recebi uma requisição!');

  // Passa para o próximo middleware
  next();
}
  • req (Request): Um objeto que contém informações sobre a requisição HTTP. Ex: req.body, req.params, req.query, req.headers.
  • res (Response): Um objeto para enviar a resposta HTTP de volta ao cliente. Ex: res.send(), res.json(), res.status().
  • next: Uma função. Quando invocada, executa o próximo middleware na pilha.
Dominando Middlewares

4. Tipos de Middlewares

Vamos explorar as diferentes formas de usar middlewares em uma aplicação Express.

Dominando Middlewares

Middleware em Nível de Aplicação

Vinculado a uma instância do app usando app.use(). É executado para todas as requisições que chegam ao seu aplicativo.

Exemplo: Logger de Requisições
Crie um arquivo logger.js:

const logRequest = (req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl}`);
  next(); // Essencial para não travar a requisição!
};

module.exports = logRequest;
Dominando Middlewares

No seu arquivo principal (app.js ou server.js):

const express = require('express');
const logRequest = require('./logger');
const app = express();

// O middleware é "usado" pela aplicação
app.use(logRequest);

app.get('/', (req, res) => {
  res.send('Página Inicial!');
});

app.listen(3000, () => console.log('Servidor rodando na porta 3000'));
Dominando Middlewares

Middleware em Nível de Roteador

Funciona da mesma forma que o middleware de nível de aplicação, mas está vinculado a uma instância de express.Router(). Ele será executado apenas para as rotas definidas naquele roteador.

Dominando Middlewares

Exemplo: Autenticação em Rotas de Admin
Crie um arquivo routes/admin.js:

Dominando Middlewares
const express = require('express');
const router = express.Router();

// Middleware de autenticação específico para este roteador
const authMiddleware = (req, res, next) => {
  const { token } = req.query;
  if (token === 'admin123') {
    next(); // Autenticado, pode prosseguir
  } else {
    res.status(401).send('Acesso não autorizado!');
  }
};

// Aplica o middleware a todas as rotas deste arquivo
router.use(authMiddleware);

router.get('/dashboard', (req, res) => {
  res.send('Bem-vindo ao Dashboard do Admin!');
});

module.exports = router;
Dominando Middlewares

Middleware de Tratamento de Erros

Este é um tipo especial. Ele possui quatro argumentos, em vez de três: (err, req, res, next). Ele permite capturar e processar erros que ocorrem nos middlewares ou rotas.

Importante: Deve ser definido por último, após todas as outras chamadas de app.use() e rotas.

Dominando Middlewares

Exemplo: Captura Geral de Erros
No seu app.js:

Dominando Middlewares
// ... (outras rotas e middlewares)

// Rota que gera um erro
app.get('/erro', (req, res, next) => {
  const err = new Error('Este é um erro de teste!');
  err.status = 500;
  next(err); // Passa o erro para o middleware de tratamento
});

// Middleware de tratamento de erros (com 4 argumentos)
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(err.status || 500).send({
    error: {
      message: err.message || 'Ocorreu um erro no servidor.',
    },
  });
});
Dominando Middlewares

Middlewares Embutidos (Built-in)

Desde a versão 4.x do Express, alguns middlewares que antes eram de terceiros foram incorporados.

  • express.json(): Analisa o corpo (body) de requisições com Content-Type: application/json. Essencial para APIs.
  • express.urlencoded({ extended: true }): Analisa o corpo de requisições de formulários (Content-Type: application/x-www-form-urlencoded).
  • express.static('public'): Serve arquivos estáticos (como HTML, CSS, imagens) de um diretório.
Dominando Middlewares

Exemplo de uso:

const express = require('express');
const app = express();

// Middleware para entender JSON
app.use(express.json());

// Middleware para servir arquivos da pasta 'public'
app.use(express.static('public'));

app.post('/api/users', (req, res) => {
  const newUser = req.body; // Graças ao express.json()
  console.log(newUser);
  res.status(201).json({ message: 'Usuário criado!', user: newUser });
});
Dominando Middlewares

Middlewares de Terceiros

Uma das maiores forças do Express é seu ecossistema. Existem milhares de middlewares no NPM para resolver problemas comuns.

  • cors: Habilita o Cross-Origin Resource Sharing.
  • helmet: Ajuda a proteger sua aplicação configurando vários cabeçalhos HTTP de segurança.
  • morgan: Um logger de requisições HTTP poderoso e customizável.
  • cookie-parser: Analisa o cabeçalho Cookie e popula req.cookies.
Dominando Middlewares

Exemplo com helmet e morgan:

npm install helmet morgan
const express = require('express');
const helmet = require('helmet');
const morgan = require('morgan');
const app = express();

app.use(helmet()); // Adiciona uma camada de segurança
app.use(morgan('dev')); // Loga requisições no console em formato 'dev'

app.get('/', (req, res) => {
  res.send('Esta aplicação está mais segura e com logs!');
});
Dominando Middlewares

5. Mão na Massa: Criando Middlewares Customizados

Vamos criar um middleware que adiciona um timestamp a cada requisição, para podermos, por exemplo, medir o tempo de processamento.

Dominando Middlewares

addTimestamp.js

const addTimestamp = (req, res, next) => {
  req.requestTime = Date.now();
  next();
};

module.exports = addTimestamp;
Dominando Middlewares

app.js

const express = require('express');
const addTimestamp = require('./addTimestamp');
const app = express();

app.use(addTimestamp);

app.get('/', (req, res) => {
  const processingTime = Date.now() - req.requestTime;
  res.send(`Requisição recebida em ${req.requestTime}. Tempo de processamento: ${processingTime}ms.`);
});

app.listen(3000);

Este exemplo mostra como middlewares podem modificar o objeto req, passando informações entre si ou para o manipulador de rota final.

Dominando Middlewares

Resumo e Pontos-Chave

  • Funções no Meio do Caminho: Middlewares interceptam requisições e respostas.
  • req, res, next: Os três pilares de um middleware.
  • A Ordem Importa: Middlewares são executados na ordem em que são definidos.
  • Não Esqueça o next(): Se o ciclo não for encerrado, chame next() para evitar que a requisição trave.
  • Poder e Flexibilidade: Use para logging, autenticação, validação, tratamento de erros e muito mais.
  • Ecossistema Rico: Explore o NPM para encontrar soluções prontas para problemas comuns.
Dominando Middlewares

Perguntas?