Atualizado em 03/07/2024!
Em outro tutorial que publiquei aqui no blog tem algum tempo, eu ensinei como usar o pacote Joi para fazer a validação de input de dados usando Node.js. No entanto, o exemplo era bem básico e rodava todo em linha de comando.
A ideia do tutorial de hoje é fazer praticamente a mesma coisa, mas em uma web API usando ExpressJS, usando da arquitetura do Express organizada em middlewares.
#1 – Setup inicial
Para o setup inicial do projeto, usarei o meu fork do projeto express-generator, cujo passo-a-passo mega resumido está abaixo (rode o terminal como administrador para funcionar o primeiro comando).
1 2 3 4 5 6 7 |
npm install -g https://github.com/luiztools/express-generator.git express --git example-2 cd example-2 npm install npm start |
Isso sobre uma aplicação Node.js muito simples usando ExpressJS e EJS.
Agora, vá no arquivo routes/users.js e altere o conteúdo para que tenhamos nessa rota uma API bem simples de usuários, apenas com GET para retornar e POST para enviar dados. O conteúdo que mostrarei neste tutorial é aplicável aos demais verbos e cenários também, bastará adaptar um pouco.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
const express = require('express'); const router = express.Router(); router.get('/', function(req, res, next) { res.json([]); }); router.post('/', (request, response) => { response.json(request.body); }) module.exports = router; |
Esta API fake apenas exibe um array vazio quando recebe um GET e devolve o body de uma requisição POST.
Experimente mandar qualquer dado no body de uma requisição POST para ela, via Postman de repente e verá que ela não faz qualquer julgamento quanto aos dados recebidos, deixando tudo passar.
Imagine o quanto isso pode ser nocivo ao seu sistema.
E enquanto eu mostrei no tutorial passado de como usar o Joi para fazer a validação dos dados recebidos frente a um schema, nós vamos recuperar aquela ideia e levá-la a outro nível no Express.
#2 – Criando o schema
Não interessa se você está salvando os seus dados em um arquivo de texto, no MongoDB ou em um banco relacional como MySQL, você vai querer validar os inputs de dados que o usuário ou cliente da API enviou antes de persisti-los na base.
Para fazer validações vamos usar o pacote Joi, um dos mais famosos para este fim na atualidade.
Instale-o na sua aplicação usando o comando abaixo.
1 2 3 |
npm i joi |
Quando estamos falando de web, é muito comum usar o padrão MVC (Model View Controller) ou alguma arquitetura inspirada nele. Neste padrão, temos uma camada da aplicação, a Model, responsável pela lógica de persistência dos dados, incluindo os schemas de validação.
Sendo assim, crie uma pasta models na raiz do seu projeto e dentro dela adicione um arquivo userSchema.js.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
const Joi = require('joi'); module.exports = Joi.object({ username: Joi.string() .alphanum() .min(3) .max(30) .required(), password: Joi.string() .pattern(/^[a-zA-Z0-9]{3,30}$/), birth_year: Joi.number() .integer() .min(1900) .max(2001), email: Joi.string() .email({ minDomainSegments: 2, tlds: { allow: ['com', 'net'] } }) }); |
Essa é a mesma validação que usei no tutorial anterior, referente ao schema de um usuário com username, password, birth_year e email, com várias regras dentro de cada campo, incluindo tipo de caracteres, tamanho mínimo e máximo, obrigatoriedade e até configuração específica no caso do email.
Este módulo de validação retorna um objeto userSchema que usaremos em nossa rota da web API para validar a entrada de dados de usuários.
#3 – Criando o middleware
Agora que temos tudo configurado e criado, basta a gente adicionar a validação na nossa rota de POST, visto que a rota GET não precisa.
A rota POST espera no request.body os dados do usuário a ser salvo no banco de dados. Mas antes de executar o callback do POST, vamos adicionar uma chamada ao nosso userSchema, para ele validar o body da requisição usando um middleware Express. Middlewares no Express são como se fossem camadas intermediárias de processamento da requisição HTTP, ou seja, ao invés de um único callback para tratar request e response, nós dividimos a responsabilidade com outras funções para aumentar o reuso, diminuir a complexidade e aumentar a facilidade de manutenção.
Abra o routes/users.js e além de adicionar mais um require ao userSchema, vamos adicionar o middleware abaixo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
const express = require('express'); const router = express.Router(); const userSchema = require("../models/userSchema"); const validationMiddleware = (request, response, next) => { const { error } = userSchema.validate(request.body) const valid = error == null; if (valid) { next(); } else { const { details } = error; const message = details.map(i => i.message).join(','); console.log("error", message); response.status(422).json({ error: message }) } } |
Este middleware utiliza o userSchema para validar a request.body e se veio um erro, coleta e formata os detalhes, imprime no console e devolve em uma resposta HTTP 422 (uma especialização do 400 Bad Request que sinaliza Unprocessable Entity, que é o caso aqui).
Para usar este middleware é muito simples, na rota POST deste mesmo routes/users.js, adicione o nome do middleware antes do callback tradicional.
1 2 3 4 5 |
router.post('/', validationMiddleware, (request, response) => { response.status(201).json(request.body); }) |
E para testar, você pode usar o Postman. Experimente dar uma estressada em possíveis valores errados para ver se a validação está a contento. Enviando uma requisição com um body correto deve resultar em um 201 Created, enquanto qualquer regra que não seja seguida, o middleware vai interromper o processamento retornando um 422 Unprocessable Entity como abaixo.
Então é isso.
Você pode criar diferentes schemas para diferentes necessidades e até criar uma função de middleware mais genérica que receba o schema por parâmetro, tornando a sua arquitetura ainda mais organizada e profissional.
Espero que tenha gostado do tutorial.
Um abraço e até a próxima!
Interessado em ver estes e outros conteúdos incríveis em videoaulas comigo? Conheça o meu curso de Node.js e MongoDB clicando no banner abaixo.
Olá, tudo bem?
O que você achou deste conteúdo? Conte nos comentários.