Validando requests no express usando Joi
Uma simples pesquisa por never trust the client no Google e você vai encontrar vários resultados sobre o porquê não devemos nunca confiar no cliente. Nesse caso, cliente remete a qualquer usuário que use sua aplicação, esteja ele bem, ou mal intencionado.
Mesmo que o client-side da sua aplicação seja desenvolvido por você mesmo, e que sua API não é exposta nem documentada em lugar nenhum, o usuário sempre poderá abrir o dev tools do navegador e "aprender" a usar a sua API apenas visualizando as requests que são feitas. Inclusive já fiz projetos pessoais para automatizar rotinas utilizando essa técnica.
Existem várias formas de se proteger de usuários mal intencionados, e a forma mais simples é a validação dos dados enviados.
Esse artigo explica e apresenta uma forma de fazer validação dos dados recebidos da request usando express e Joi que resolve o problema de forma eficaz e sem adicionar muita complexidade ao projeto como um todo.
Para começarmos, precisamos de um middleware que funcione em qualquer rota e garanta uniformidade na interface de resposta. O importante nesse ponto é que sejam validados apenas os dados sem gerar complexidade desnecessária ou aglutinar responsabilidades de outros trechos do projeto:
Agora que temos a função que fará a validação e responderá a request em caso de erro, precisamos das regras de validação. E para criá-las precisamos de um schema do Joi com as regras que fizerem sentido para nossa aplicação. Por exemplo:
Agora basta unir os dois pontos declarando a utilização do middleware com a regra que deve ser utilizada:
E com tudo isso, teremos ponto central onde toda validação é realizada.
Bônus: olhando a primeira linha do middleware de validação, veremos que o objeto req
inteiro é passado para ser validado. Esse objeto possui todas informações a respeito da request recebida. Algumas dessas informações são enviadas pelo usuário e podem ser validadas:
params
para validar parâmetros da URL;query
para validar parâmetros de query string;- e
headers
para validar, bom, os headers.
Para validar esses parâmetros, basta adicionar uma destas chaves no mesmo nível da chave body
no schema de validação utilizado no exemplo.
Recomendo fortemente a leitura desse artigo para isolar melhor as responsabilidades de cada parte do código. Assim, trocaríamos o res.send
do middleware de validação para o seguinte
Onde o JoiValidationError
seria responsável por transformar o erro do Joi no formato esperado e o error handler seria responsável por responder a request.
Esse artigo não cita em momento algum testes para o código sugerido, mas testá-lo unitariamente não deveria ser um desafio muito grande.
Esse é um formato que cheguei depois de um tempo brincando em uma API onde aplico over-engineering para explorar novas formar de se resolver um problema. Você pode encontrar mais exemplos no repositório onde mantenho esse código.