Gerenciar o ciclo de vida de uma solicitação com middleware

Concluído

A Tailwind Traders gostaria de proteger sua API Web. Em alguns casos, quando uma solicitação chegar em um aplicativo Web, é necessário verificar:

  • Autenticação: quem é o usuário
  • Autorização: o que o usuário tem permissão para ver ou fazer

Etapas da solicitação

Considere o processamento de uma solicitação como uma série de etapas. Quando o usuário precisa estar conectado para processar um recurso, as etapas são semelhantes às seguintes:

  1. Pré-processamento: uma etapa opcional para executar o código antes que a solicitação seja processada.

    Um exemplo é determinar se o usuário enviou as credenciais adequadas por meio de um cabeçalho de solicitação. Se as credenciais forem verificadas, envie a solicitação para a próxima etapa. Se o log falhar, o servidor retornará uma resposta HTTP 401.

  2. Processamento: processe a solicitação, como falar com algum tipo de fonte de dados, como um banco de dados ou um ponto de extremidade de API.

    Essa etapa retorna o recurso, desde que a solicitação o solicite corretamente.

  3. Pós-processamento: uma etapa opcional para executar o código após a conclusão da solicitação.

    Um exemplo é registrar os resultados para fins de monitoramento.

A estrutura Express conta com suporte interno para processar uma solicitação dessa maneira. Para executar um pré ou pós-processamento de uma solicitação, implemente o método use() em seu objeto Express app com o seguinte formulário de sintaxe:

app.use((req, res, next) => {})

O método passado para o método use() tem os seguintes parâmetros:

  • req: a solicitação de entrada que contém os cabeçalhos de solicitação e a URL de chamada. Ele também poderá ter um corpo de dados se o cliente enviou dados com a solicitação.
  • res: um fluxo de resposta para uso em gravações de informações, como cabeçalhos e dados que você deseja enviar novamente para o cliente autor da chamada.
  • next: A próxima função de middleware na pilha. Se a função next() não for chamada, o processamento da solicitação será interrompido. Se a solicitação obtiver êxito, é aconselhável chamar next() para fazer alterações na resposta ou registrar os resultados.

Pipeline de solicitação

Se você tem rotas que se beneficiam de ter middleware de pré ou pós-processamento, configure as funções no arquivo de código-fonte para que:

  • Middleware que precisa ser executado antes da solicitação (pré-processamento) é definido antes da solicitação real.
  • Middleware que precisa ser executado após a solicitação (pós-processamento) é definido após a solicitação real.

Veja este exemplo:

app.use((req, res, next) => {
  // Pre request
})
app.get('/protected-resource', () => {
  // Handle the actual request
})
app.use((req, res, next) => {
  // Post request
})

app.get('/login', () => {})

Você também pode executar middleware de pré-processamento como um argumento para o manipulador de solicitação:

app.get(
  '/<some route>',
 () => {
   // Pre request middleware
 }, () => {
   // Handle the actual request
 })

A ordem das funções de middleware no Express.js é crucial porque elas são executadas sequencialmente, na ordem em que são definidas no código. Isso significa que, se uma função middleware for colocada após um manipulador de rotas, ela não será executada para essa rota.

Melhores práticas de gerenciamento de rotas

Confira algumas melhores práticas para gerenciar a ordem das funções de middleware:

  • Coloque o middleware global na parte superior: As funções de middleware que se aplicam a todas as rotas devem ser colocadas na parte superior do código, antes dos manipuladores de rota. Isso garante que elas sejam executadas para cada solicitação.

  • Ordenar middleware por especificidade: As funções de middleware mais específicas devem ser colocadas após as mais genéricas. Dessa forma, as funções de middleware genéricas podem manipular tarefas comuns para todas as rotas e as específicas podem manipular tarefas para rotas específicas.

  • Posicione o middleware de tratamento de erros por último: As funções de middleware com quatro argumentos são tratadas como middleware de tratamento de erros. Elas devem ser posicionadas no final da pilha de middleware, depois de todos os outros manipuladores de rotas e middleware.

Veja um exemplo:

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

// Global middleware
app.use((req, res, next) => {
  console.log('This is a global middleware');
  next();
});

// Route handler
app.get('/', (req, res, next) => {
  console.log('This is a route handler');
  next();
});

// Specific middleware
app.use((req, res, next) => {
  console.log('This is a specific middleware');
  next();
});

// Error-handling middleware
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

app.listen(3000);