Tutorial - Adonis Validator
O Adonis simplifica a validação de dados de entrada dos usuários de uma forma que você vai amar. 😍
Você pode trabalhar com os validadores do Adonis de duas formas, manualmente (aplicando a validação dentro dos controllers ) ou validadores de rotas. Neste post iremos falar deste último, dos validadores de rotas.
Eu recomendo utilizar os validadores de rotas, uma vez que eles ficam em arquivos separados dos controllers (veremos isso logo em diante). Dessa forma nosso código fica alinhado com as boas práticas de design patterns.
Para este artigo, estou utilizando um exemplo de aplicação somente de API, não tendo views no projeto.
Instalando o Adonis Validator
Por padrão, ao criar um projeto Adonis o validator não é adicionado. Para instalar é muito simples. Execute o seguinte comando no terminal.
adonis install @adonisjs/validator
Agora é preciso registrar o provider do validator. Navegue até o arquivo start/app.js
e adicione o provider da seguinte forma:
const providers = [
'@adonisjs/validator/providers/ValidatorProvider'
]
Validator no controller
A critério de comparação, vamos ver como seria a validação dos dados direto no controller.
Adicionar as validações diretamente no controller é a forma mais fácil de se garantir a validação dos dados de entrada na nossa aplicação. No entanto, essa não é a forma mais adequada de se fazer.
A seguir, temos um exemplo hipotético de um controller de posts chamado PostController.js
. O pseudo código abaixo ilustra o método store
do controller com a respectiva validação dos dados.
'use strict'
const Post = use('App/Models/Post');
const { validateAll } = use('Validator');
class PostController {
async store({request, response, auth}){
// regras de validação
const rules = {
title: 'required|min:25',
body: 'required'
}
// mensagens tratadas de falha na validação
const messages = {
'title.min': 'O campo título está muito pequeno',
'title.requerid': 'O título deve ser informado',
'body.required': 'O corpo do post deve ser informado'
}
const validate = await validateAll(request.all(), rules, messages);
if (validate.fails()){
return response.status(401).send({message: validate.messages()})
}
const { id } = auth.user;
const {title, body} = request.all();
const post = await Post.create({title, body, user_id: id});
return post;
}
...
}
module.exports = PostController
Este exemplo, apesar de funcionar bem, adiciona uma carga extra de responsabilidade sobre o método store
que deveria ser responsável somente por criar um novo recurso na nossa API.
Dito isto, vamos ver agora como passar os validadores para arquivos específicos e removê-los dos controllers.
Criando validadores
O Adonis oferece um comando no terminal que cria pra gente os validators, em arquivos e pastas específicas onde eles devem ficar para serem usados diretamente nas rotas.
Para criar um novo validator, use o seguinte comando:
adonis make:validator StorePost
O último argumento deste comando é o nome do validator que será criado. É interessante utilizar um nome que remeta ao que o validator se trata. Neste caso, criei um validator par ao método store
do controller de posts.
Após rodar o comando, se tudo correu bem você verá um novo arquivo na pasta app/Validators
com o nome que você deu. Neste arquivo iremos adicionar as validações que quisermos.
Agora, vamos deixar o arquivo de validator com as mesma regras de validação que tínhamos no controller PostController
.
'use strict'
class StorePost {
get validateAll () {
return true
}
async fails (errorMessages) {
return this.ctx.response.send(errorMessages)
}
get rules () {
return {
title: 'required|min:25',
body: 'required'
}
}
get messages () {
return {
'title.min': 'O campo título está muito pequeno',
'title.requerid': 'O título deve ser informado',
'body.required': 'O corpo do post deve ser informado'
}
}
}
module.exports = StorePost
Você já deve ter observado que o arquivo de validação é composto por vários métodos e alguns deles não parecem nem de perto com o que tínhamos lá no PostController
. Pois bem, vamos à explicação de cada um.
O método get validadeAll()
diz pro Adonis validar todas as regras de validação para só depois retornar as falhas. Dessa forma, todas as mensagens de erro na validação serão retornadas de uma única vez, eu você pode mostrar isso para seu usuário, se desejar.
O método async fails (errorMessages)
diz pro Adonis que ao identificar falhas na validação das regras ele deve retornar as falhas pra quem fez a requisição. Se esse método estiver ausente, o Adonis irá retornar uma mensagem genérica de falha na validação dos campos de entrada.
Os métodos get rules ()
e get messages ()
são equivalentes às constantes rules
e messages
definidas no PostController
e definem respectivamente quais as regras para validar os dados de entrada e as mensagem personalizadas que serão exibidas caso haja falha.
Adicionando o Validator em uma Rota
Bom, depois de esclarecer os detalhes do validador, chegou a hora de adicionar o validator nas nossas rotas.
Route.post('posts', 'PostController.store').validator('StorePost')
Realmente é tão simples quanto parece. Dessa forma, ao acionar a rota /posts
da nossa API os dados de entrada serão submetidos ao validator StorePost
e só após todas as validações passarem que o controller será chamado.
Dessa forma, passando a validação para um arquivo específico e o chamando pela rota, o nosso método store
do PostController
passa a ter somente a responsabilidade de persistir os dados.
O controller ficaria algo como isso:
'use strict'
const Post = use('App/Models/Post');
class PostController {
async store({request, response, auth}){
const { id } = auth.user;
const {title, body} = request.all();
const post = await Post.create({title, body, user_id: id});
return post;
}
...
}
module.exports = PostController
Muito mais simples e fácil de entender o que ele faz, não? 😎
Concluindo
O objetivo desse post foi mostrar uma forma simples, porém eficaz de se utilizar os validators do Adonis. Vimos que chamar o validador através da rota e remover a responsabilidade de validar os dados do controller é uma opção que deixa nosso código mais limpo, e também muito mais elegante.