Aumentando a Produtividade com o Class-Validator no DTO do NestJS
Tags: nestjs, productivity, dto, backend
Published: 2023-07-20 23:26:39

## Intro
No mundo acelerado do desenvolvimento de software, ser produtivo é crucial. Reduzir o tempo gasto na escrita de código repetitivo e de validação de dados pode ser uma tarefa desafiadora. Felizmente, o NestJS, um popular framework para construção de aplicações Node.js, oferece uma solução chic para esse problema - o **class-validator**. Neste artigo, exploraremos como o class-validator pode ser utilizado no DTO (Data Transfer Object) do NestJS, proporcionando uma maneira fácil e eficiente de validar os dados recebidos e, assim, aumentar sua produtividade.
![Alt Text](https://media.giphy.com/media/pT4pmRFs15Yg8/giphy.gif)


## O que é o Class-Validator
O class-validator é uma biblioteca de validação para classes em TypeScript. Ele fornece uma maneira declarativa de definir as regras de validação, eliminando a necessidade de escrever manualmente. Essa biblioteca é extremamente útil no contexto do NestJS, pois pode ser integrada perfeitamente aos DTOs usados para transferir dados entre as camadas da aplicação.

Github do projeto class-validator: https://github.com/typestack/class-validator

Esse pacote não é específico no NestJS, mas resolvi escrever esse artigo com o framework pois sou modinha e no momento ele está me fazendo muito feliz a cada descoberta kkkkkk Se você gostar tanto como eu, poderá implementar facilmente em qualquer aplicação escrita em Typescript.

## Benefícios do Class-Validator no DTO do NestJS
Ao utilizar o class-validator no DTO do NestJS, teremos benefícios significativos:

1. Redução do código repetitivo: O class-validator permite definir as regras de validação diretamente nas propriedades do DTO, eliminando a necessidade de escrever funções de validação separadas para cada campo. Isso reduz drasticamente a quantidade de código repetitivo, tornando a manutenção e evolução do código muito mais fácil.

2. Melhor legibilidade: Ao declarar as regras de validação diretamente no DTO, o código se torna mais legível e autoexplicativo. As regras de validação ficam intimamente ligadas às propriedades correspondentes, tornando o código mais compreensível para outros desenvolvedores.

3. Validações pré-definidas: O class-validator oferece uma infinidade de validações pré-definidas, como validação de tipo, validação de tamanho mínimo/máximo, validação de formato de e-mail, entre outras. Essas validações podem ser facilmente aplicadas às propriedades do DTO com o uso de decoradores, poupando tempo e esforço.

4. Validações personalizadas: Além das validações pré-definidas, o class-validator permite a criação de validações personalizadas para atender às necessidades específicas da aplicação. Isso nos dá uma flexibilidade adicional para lidar com casos de validação mais complexos e específicos do domínio.

![Alt Text](https://media.giphy.com/media/MypFo3No7gHLywrjrM/giphy.gif)

## Exemplo prático
Vamos implementar um exemplo onde temos uma API de criação de postagens em um blog. Para criar uma nova postagem, precisamos garantir que o título seja uma string com no mínimo 5 caracteres e que o conteúdo da postagem não esteja vazio. Além disso, cada postagem pode ter uma lista de tags associadas a ela. Veja o exemplo:

``` typescript
import { Controller, Post, Body } from '@nestjs/common';
import { IsString, MinLength, IsNotEmpty, IsArray, ArrayNotEmpty, ArrayMaxSize, ArrayUnique } from 'class-validator';

class CreatePostDto {
  @IsString()
  @MinLength(5)
  title: string;

  @IsString()
  @IsNotEmpty()
  content: string;

  @IsArray()
  @ArrayNotEmpty()
  @ArrayMaxSize(5)
  @ArrayUnique()
  tags: string[];
}

@Controller('posts')
export class PostsController {
  @Post()
  createPost(@Body() createPostDto: CreatePostDto) {
    // Restante da lógica para criar a postagem
  }
}
```
No exemplo acima, temos o DTO CreatePostDto, que possui as propriedades title, content e tags. Utilizamos decorators específicos para cada propriedade:

Para o `title`, utilizamos:
@IsString() para garantir que seja uma string;
@MinLength(5) para exigir um mínimo de 5 caracteres no título.

Para o `content`, utilizamos:
@IsString() para garantir que seja uma string;
@IsNotEmpty() para garantir que não esteja vazio.

Para as `tags`, utilizamos uma série de decorators para validar a lista de tags:
@IsArray() para garantir que seja um array;
@ArrayNotEmpty() para garantir que não esteja vazio;
@ArrayMaxSize(5) para limitar o tamanho máximo do array em 5 elementos;
@ArrayUnique() para garantir que não haja valores duplicados na lista.

Assim, ao receber uma requisição no endpoint de criação de postagens, o NestJS aplicará as regras de validação definidas no DTO CreatePostDto. Se algum dos campos não atender às regras de validação, uma resposta de erro será retornada automaticamente.

O uso do Class Validator nesse contexto permite garantir que os dados de entrada atendam aos critérios estabelecidos para a criação de uma postagem, como o tamanho mínimo do título, a presença de conteúdo e a validação das tags associadas à postagem. Isso contribui para a integridade dos dados, a consistência das informações em sua API e felicidade do time hehe

![Alt Text](https://media.giphy.com/media/10UeedrT5MIfPG/giphy.gif)

Se você não estiver utilizando o Class Validator, precisará implementar as verificações de validação manualmente em seu código. Aqui está um exemplo de como você poderia realizar as mesmas validações sem o uso do Class Validator:

``` typescript
import { Controller, Post, Body, BadRequestException } from '@nestjs/common';

class CreatePostDto {
  title: string;
  content: string;
  tags: string[];
}

@Controller('posts')
export class PostsController {
  @Post()
  createPost(@Body() createPostDto: CreatePostDto) {
    if (!createPostDto.title || createPostDto.title.length < 5) {
      throw new BadRequestException('O título deve ser uma string com no mínimo 5 caracteres');
    }

    if (!createPostDto.content || createPostDto.content.trim() === '') {
      throw new BadRequestException('O conteúdo da postagem não pode estar vazio');
    }

    if (!createPostDto.tags || !Array.isArray(createPostDto.tags) || createPostDto.tags.length === 0) {
      throw new BadRequestException('A lista de tags deve ser um array não vazio');
    }

    const uniqueTags = Array.from(new Set(createPostDto.tags));
    if (uniqueTags.length !== createPostDto.tags.length) {
      throw new BadRequestException('A lista de tags não pode conter valores duplicados');
    }

    if (createPostDto.tags.length > 5) {
      throw new BadRequestException('A lista de tags não pode ter mais do que 5 elementos');
    }

    // Restante da lógica para criar a postagem
  }
}
```
Nesse exemplo, dentro do método createPost, você realiza manualmente as verificações de validação para o DTO CreatePostDto.

![Alt Text](https://media.giphy.com/media/6Q3M4BIK0lX44/giphy.gif)

Para o campo title, você verifica se ele existe e se possui pelo menos 5 caracteres.
Para o campo content, você verifica se ele existe e se não está vazio, removendo espaços em branco extras.
Para o campo tags, você verifica se ele existe, é um array não vazio, não possui valores duplicados e tem no máximo 5 elementos.
Se alguma das verificações falhar, você pode lançar uma exceção adequada (como BadRequestException no NestJS) para indicar que a validação falhou e retornar uma resposta de erro.

## Conclusão
Embora seja possível realizar as validações manualmente, o uso do Class Validator simplifica o processo e fornece uma abordagem declarativa e consistente para validar objetos. Com validações pré-definidas e personalizadas, ele também oferece recursos adicionais, como mensagens de erro customizadas e validação de objetos aninhados. Portanto, o Class Validator pode ser uma opção mais produtiva e conveniente para lidar com a validação em suas APIs.

Espero que esse singelo artigo tenha demonstrado como o uso do class-validator no DTO do NestJS pode melhorar a produtividade e facilitar suas implementações no dia a dia. Ao utilizar essa abordagem em seus projetos, você estará agilizando o desenvolvimento e garantindo a integridade dos dados recebidos. Experimente em seu próximo projeto!

Obrigada por ler até aqui :D
![Alt Text](https://media.giphy.com/media/3coysfsJSiqW3J3Xzm/giphy.gif)