Iniciando com middlewares no Express.js

Uma das principais funcionalidades dentro de frameworks web em Node.js é a utilização de middlewares. Hoje falaremos deles no Express.js, para entender como funciona fluxo de requisições e respostas  que é totalmente baseado em middlewares, deixando as coisas mais interessantes.

Começando com middlewares

Para ficar mais claro, vou associar o Express a brincadeira de telefone sem fio. Sim, isso mesmo, mas o que uma coisa tem a ver com a outra? Bom o Express é aquele que passa a primeira informação e nela contém tudo que é relacionado ao serviços Web e a seus protocolos e métodos.

Vindo a primeira informação ela passa por uma fila, e assim como na brincadeira, o middleware pode alterar, adicionar ou apagarinformações. É importante dizer que no meio do caminho pode-se “acabar” com a brincadeira, como é o caso do res.render, res.send ou res.end que emitem os cabeçalhos de respostas (protocolo HTTP). Vejamos esses códigos.

const express = require('express');

const app = express();

// Middleware #1
app.get('/', (req, res, next) => {
  res.locals.hello = 'Hello World';
  next();
}); 

// Middleware #2
app.get('/', (req, res) => {
  return res.send(res.locals.hello);
});

// Middleware #3
app.get('/', (req, res) => {
  res.send('Eu nunca serei chamado! T.T');
});

app.listen(3000);

Execute o código com nodejs index.js e acesse htpp://localhost:3000

É importante entender que as variáveis req e res fazem parte das requisições e respostas respectivamente. Tanto é que com o req.body conseguimos os valores vindos de um formulário e com o res.render conseguimos renderizar uma página.

Para reforçar como funciona o fluxo de requisição no middleware veja a imagem:

Fluxo do funcionamento do middleware no Express.js

Na brincadeira, iniciamos passando uma informação para a primeira pessoa de uma fila e ela para a próxima, e para isso acontecer no nosso código precisamos do next() pois ele é o responsável por chamar o próximo middleware.

// Middleware #1
app.use((req, res, next) => {
  res.locals.hello = 'Hello World';
  next();
}); 

Ainda na primeira rota, utilizamos a variável res.locals.hello para guardar uma string, e é essa informação que será passada para os próximos middlewares dessa rota. Observe que a primeira informação foi alterada e que a brincadeira segue com o next.

// Middleware #2
app.get('/', (req, res) => {
  return res.send(res.locals.hello);
});

Na segunda rota, resgatamos o valor inserido no primeiro middleware e usamos ele no res.send.  Quando utilizamos esse res.send estamos montando o nosso cabeçalho e ele não pode ser reescrito. Por isso é altamente recomendado prefixar o return como fizemos acabando com o fluxo da brincadeira sem erros.

// Middleware #3
app.get('/', (req, res) => {
  res.send('Eu nunca serei chamado! T.T');
});

Como você deve estar imaginando, a terceira rota nunca será exibida pois com o return já temos nossa páginas sendo entregue ao cliente.

Todas as rotas que chamei anteriormente são middlewares, que utilizam a mesma rota e o mesmo método (GET). É um exemplo simples e pouco utilizado, pois não usaria com total poder os middlewares. É nessa parte o Express.js se diferencia da nossa brincadeira, ele separa seus middlewares por métodos, rotas e sub-rotas.

Middlewares genéricos

Podemos fazer com que um middleware seja utilizado por vários métodos(GET, POST por exemplo) e também definirmos se será utilizado qualquer rota ou a partir de uma rota específica para suas sub-rotas. Utilizaremos o método app.use para fazer isso.

// Middleware #1
app.use((req, res, next) => {
  res.locals.hello = 'Hello World';
  next();
}); 

// Middleware #2
app.get('/', (req, res) => {
  return res.send(res.locals.hello);
});

Veja que com app.use não utilizamos uma rota, apenas pegamos as informações que ele possui, alteramos e mandamos para o próximo. É assim que a grande maioria de middlewares externos trabalham no Express.js.

O interessante é que todas as rotas que acessarmos depois desse middleware teremos essa informação disponível para todos os métodos.

Poderíamos definir uma rota /app que precisa de autorização para acessar o dashboard de usuário por exemplo, teríamos algo parecido:

app.use('/app', (req, res, next) => {
  if (!usuariologado) {
    return res.redirect();
  }
  next();
});

Consequentemente, todas as sub-rotas de /app utilizarão esse middleware antes de ser executada. Isso acontecerá quando acessarmos /app/dashboard.

Não se esqueça que os middlewares trabalham em fila, por isso você precisa utilizar os middlewares que tratam as informações antes de chamar uma rota que devolva os cabeçalhos  para o cliente. Você também não consegue pegar uma informação alterada antes de passar pelo middleware propriamente dito.

É hora de dar tchau

Bom galera, é isso!!

Perceba que não é difícil quanto parece. Agora é só praticar que estarás refinado para utilizar middlewares sem medo no seu próximo App. Afinal, a prática leva a perfeição.

Ah, lembrando que nesse Post utilizei a versão mais nova do Node.js e por isso consigo utilizar as features das versões mais recentes do ECMAScript. Se você ainda não  utiliza essas funcionalidades se liga nesse curso gratuito sobre JavaScript com ES6+ que preparamos para você.

Veja o projeto completo no nosso github: https://github.com/Rocketseat/blog-express-middlewares

Grande abraço.