Construindo uma API com NestJS, PostgreSQL e Docker — Parte 3: Finalizando nosso CRUD de usuários

Iago Maia Silva
4 min readMar 2, 2020

--

NestJS — Um framework Node.js para construção de aplicações confiáveis e escaláveis.

Recentemente comecei a estudar Node pensei em desenvolver uma API com funcionalidades básicas, que praticamente todo projeto precisa, como forma de me familiarizar com a linguagem. Para me auxiliar nessa tarefa utilizei o framework NestJS. Nesta série de tutoriais vou compartilhar o que aprendi.

Série completa:

Irei atualizando essa lista com links para as devidas partes conforme eu for postando!

Requisitos

O código da etapa anterior se encontra em um repositório no meu GitHub:

TL;DR

O código desta etapa também se encontra em um repositório no meu GitHub:

Finalizando o CRUD de usuários

Com a etapa de autenticação e autorização concluídas podemos finalizar nosso módulo de usuários.

Como criamos um módulo auth para tratar da criação de conta de usuários comuns e login todas as outras operações referentes a usuários no módulo users vão ser protegidas por autenticação e também por autorização. Para isso, ao invés de protegermos endpoint por endpoint da nossa aplicação, podemos colocar nosso decorator @UseGuards junto ao nosso decorator @Controller(‘users’) ficando da seguinte forma:

users.controller.ts

Buscar dados de um usuário por ID

O primeiro endpoint que vamos adicionar à api será para buscar um usuário com o ID informado como parâmetro na URI.

Primeiro vamos criar o método no nosso users.service.ts:

users.service.ts

Agora vamos chamar esse método de dentro do nosso controller, criando um endpoint:

users.controller.ts

Alguns detalhes para se observar:

  • Foi utilizado o decorator @Get. Isso por que o método que utilizaremos para acessar esse endpoint será o GET. Vamos utilizar diferentes métodos (ou verbos) HTTP nessa etapa do tutorial, visto que cada um é um indicador da ação que será realizada pelo endpoint, seguindo boas práticas para construção de APIs.
  • Passamos a string ‘:id’ como parâmetro para o decorator @Get. Isso indica que a API espera receber um parâmetro na url e esse parâmetro poderá ser acessado pelo identificador ‘id’.
  • No nosso método findUserById passamos como primeiro parâmetro o id informado na url, e pudemos obter esse valor utilizando o decorator @Param, passando como argumento o nome que utilizamos no decorator do método.

Alterar dados de um usuário

Nosso próximo endpoint irá alterar os dados de um usuário já cadastrado. Para isso, primeiro vamos criar um DTO para representar o conjunto de dados de um usuário que poderão ser alterados. Na pasta dto dentro de users vamos criar o update-users.dto.ts:

update-user.dto.ts

Agora, no users.service.ts, vamos adicionar o método que irá alterar os dados do usuário:

users.service.ts

E por último, criar o endpoint no controller:

user.service.ts

Reparem que, além de utilizarmos um novo verbo HTTP (PATCH), combinamos o uso do decorator @Body com o decorator @Param. Também fizemos uso do decorator @GetUser, criado por nós mesmo no tutorial anterior.

Também realizamos uma pequena validação de permissão, já que além de um usuário administrador poder alterar dados dos outros usuários, também precisamos dar a permissão para que um usuário possa alterar seus próprios dados.

Deletar Usuário

Nosso próximo endpoint irá deletar um usuário com o ID informado na URL. Vamos criar o método no users.service.ts:

users.service.te

E logo em seguida, adicionar o endpoint no users.controller.ts:

users.controller.ts

Buscar usuários com um filtro

O último endpoint restante trará a funcionalidade do nosso client buscar vários usuários que atendam a critérios especificados. Para isso, vamos criar um DTO para representar os possíveis filtros da nossa aplicação.

Antes de tudo, vamos criar uma pasta shared dentro de src e dentro de shared vamos criar uma outra pasta chamada dto. Dentro dela vamos criar um arquivo base-query-parameters.dto.ts:

base-query-parameters.dto.ts

Nesse arquivo declaramos uma classe abstrata com alguns parâmetros que serão comuns a todas requisições de busca com filtros:

  • sort: Reponsável por passar a string representando um objeto javascript com informações a respeito de como os dados devem ser ordenados ao serem buscados no banco de dados. Como estamos passando esse parâmetro como um Query Parameter na URL, é interessante o client utilizar o JSON.stringify() para converter o objeto em string. Por exemplo:
Você pode executar esses dois comandos no próprio console do navegador para conferir!
  • page: Para dar suporte à paginação, informa qual a página dos resultados está sendo consultada pelo client (será utilizada para definirmos quantos dados devemos pular ao consultar o banco de dados)
  • limit: Quantidade de dados a serem retornados por página

Com isso agora podemos criar o arquivo find-users-query.dto.ts, dentro de users/dto:

Como nosso método de buscar usuários pode ficar bem extenso, vamos escrevê-lo dentro do nosso Repository ao invés de dentro do Service:

user.repository.ts

Alguns detalhes importantes do método findUsers:

  • Nas primeiras linhas do método executamos algumas validações de parâmetros para garantir um bom funcionamento do código.
  • Quando executamos a função createQueryBuilder passamos como argumento a string ‘user’. Essa string será o alias utilizado durante a montagem da query.
  • Após chamarmos query.where() pela primeira vez nós passamos a chamar o método query.andWhere(). Fazemos isso pois se chamarmos o método query.where() novamente ele irá substituir toda nossa query ao invés de adicionar uma nova condição.
  • Para executarmos a query nós chamamos o método query.getManyAndCount(). Esse método nos retorna dois valores: o primeiro são os usuários encontrados, o segundo o total de dados que satisfazem as condições especificadas, ignorando a paginação. Isso é muito útil para que nosso client possa exibir os dados utilizando a paginação do servidor.

Agora podemos chamar essa função do nosso users.service.ts:

users.service.ts

Por fim, vamos adicionar o endpoint ao nosso controller:

users.controller.ts

Todos esses endpoints podem ser testados utilizando o Postman!

Com isso concluímos a terceira parte do nosso tutorial. Na próxima parte vou falar sobre como adicionar logs à nossa API utilizando Interceptors!

--

--