Desenvolvimento Back-end Node

Criando o primeiro CRUD com NestJS

Neste artigo veremos como criar um CRUD com NestJS, o passo a passo utilizando ferramentas como o TypeORM e o banco de dados SQLite.

7 dias atrás

No post anterior sobre NestJS aprendemos a como criar nosso primeiro projeto, o clássico Hello World a partir do Nest CLI, uma ferramenta por linha de comando que permite criar arquivos e estruturas de forma prática e rápida. Agora vamos dar mais um passo e criar nosso primeiro CRUD (Create, Read, Update, Delete) com NestJS.

Lembrando que você pode acessar a documentação do Nest CLI para se aprofundar nos recursos que ele possui.

TypeScript - Fundamentos
Curso TypeScript - Fundamentos
Conhecer o curso

Criando Projeto do Zero

Caso você não tenha o ambiente Node.js e NestJS instalado, veja os seguintes artigos:

Após as instalações e configurações feitas, vamos criar nosso projeto utilizando o Nest CLI com o seguinte comando no terminal:

nest new crud-project

O comando acima irá criar os arquivos para a base do nosso projeto e instalar o package manager que vamos utilizar (você pode escolher entre npm, yarn ou pnpm). Para este artigo escolhi o npm.

Ao final da execução do comando, teremos uma estrutura da seguinte forma:

Ótimo! A base da nossa aplicação já está criada, neste exemplo vamos fazer um gerenciador de usuários, para isto precisamos criar toda a estrutura que irá prover o CRUD, como os arquivos referentes as camadas de entidade, controller, service e repository:

  • Entidade: são os modelos da aplicação que irão espelhar as tabelas do banco de dados.
  • Controller: é a camada responsável pelas rotas, respostas e requisições.
  • Service: é a camada responsável pela aplicação das regras de negócio.
  • Repository: é a camada responsável pela comunicação com o banco de dados.

Mais uma vez podemos utilizar o Nest CLI para nos auxiliar na criação destes arquivos, para isto vamos utilizar o comando:

nest g res users --no-spec

Obs.: Antes de utilizar o comando verifique o diretório do projeto, após criarmos o projeto com o nest new nome-do-projeto, provavelmente será necessário acessar pelo terminal o diretório criado, portanto, com o comando cd nome-do-projeto.

Explicando este comando, a flag g representa o comando generate, ou seja, estamos solicitando que o Nest CLI gere um arquivo, combinando a flag res estamos apontando para gerar um resource, assim, criando todos os arquivos referente a estrutura do Nest para a entidade users.

A flag --no-spec é utilizada para não gerar os arquivos de teste, que não serão necessários para este artigo, mas caso seja interessante para o seu projeto, basta ignorar.

Antes de gerar os arquivos, o Nest CLI irá perguntar qual padrão que será utilizado, como REST, GraphQL, Microservice, etc. Para fins de exemplo, iremos utilizar o padrão REST.

Após a execução do comando, teremos a estrutura do nosso domínio users criada automaticamente:

Algo importante a complementar é que além de gerar os arquivos, o Nest CLI também agiliza na importação dos módulos. Como criamos o novo domínio users, é necessário a importação referente a este domínio no módulo principal da nossa aplicação, o app.module:

Perceba que o UsersModule foi importado automaticamente, isso é importante pois além de poupar tempo de quem está desenvolvendo também elimina possíveis erros que podem ser ocasionados por esquecimento ou erros de digitação.

Definindo entidade user e configurando banco de dados

Node.js - Fundamentos
Curso Node.js - Fundamentos
Conhecer o curso

Neste momento precisamos definir a nossa entidade user e quais propriedades ela terá. Para facilitar vamos ter apenas três propriedades: id, nome, idade.

O arquivo user.entity.ts ficará como abaixo:

export class User {
  id: number;
  nome: string;
  idade: number;
}

Perfeito! Temos a nossa entidade já com suas devidas propriedades, mas precisamos ter um banco de dados para salvar e manipular essas informações, para isso, vamos utilizar o TypeORM com o SQLite para fins didáticos. Não se preocupe sobre o ORM, vamos nos aprofundar nele em posts futuros. Lembrando que o foco deste artigo é que você consiga criar seu CRUD com NestJS.

Para instalar o TypeORM e o driver de conexão do SQLite vamos utilizar o npm, com o seguinte comando:

npm i @nestjs/typeorm typeorm sqlite3

Após a instalação, vamos criar o arquivo de configuração do banco de dados no diretório /src e vamos chama-lo de ormconfig.ts:

import { DataSourceOptions } from 'typeorm';

export const config: DataSourceOptions = {
  type: 'sqlite',
  database: '.db/sql',
  synchronize: true, // Obs: use synchronize: true somente em desenvolvimento.
  entities: [__dirname + '/**/*.entity{.ts,.js}'],
};

E então importar a configuração no modulo da aplicação app.module.ts, passando a constante config no TypeOrmModule.forRoot(), como abaixo:

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UsersModule } from './users/users.module';
import { config } from './ormconfig';

@Module({
  imports: [UsersModule, TypeOrmModule.forRoot(config)],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

O próximo passo será configurar a entidade users para que o TypeORM mapeie e crie o espelho da tabela no banco:

import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn('increment')
  id: number;

  @Column()
  nome: string;

  @Column()
  idade: number;
}

Veja que utilizamos o decorator @Entity() para apontar que a classe User é uma entidade, e suas propriedades sendo colunas, assim como o id sendo uma chave primária.

Desta forma podemos testar se tudo está ocorrendo conforme o esperado, vamos executar nossa aplicação e cruzar os dedos! 🤞

Para isto, basta executar o seguinte comando:

npm run start

Finalmente, vamos ao CRUD com NestJS!

Express - Desenvolvendo aplicações web
Curso Express - Desenvolvendo aplicações web
Conhecer o curso

Agora que já temos a nossa aplicação criada e configurada, nós vamos começar de fato com o desenvolvimento das funcionalidades de CRUD.

Criando um usuário

Primeiramente vamos criar um usuário, para isto precisamos definir as propriedades no arquivo create-user.dto, neste caso, o id será gerado automaticamente, portanto vamos passar o nome e idade:

export class CreateUserDto {
  nome: string;
  idade: number;
}

Ótimo, agora o próprio TypeORM nos fornece uma série de recursos que podemos utilizar em nossa aplicação, como injetar um repositório referente a entidade que estamos trabalhando na camada de service, como por exemplo no users.service.ts:

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
  ) {}
  create(createUserDto: CreateUserDto) {
    return this.userRepository.save(createUserDto);
  }
}

Para isso, utilizamos o @InjectRepository(User) e então criamos um objeto do tipo Repository passando no construtor da classe UsersService, utilizando a injeção de dependências. Desta forma podemos chamar os métodos que irão se comunicar com o banco e efetivamente manipular os dados, neste primeiro exemplo estamos criando um usuário utilizando o método create(), e agora vamos para a camada do controller.

O controller é o responsável pelas rotas e pelas requests/responses, para criar um recurso vamos utilizar o verbo POST e chamar o método create do service, conforme abaixo:

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }
}

Obs: Caso você não tenha conhecimento em APIs REST e protocolo HTTP recomendo fortemente a leitura do artigo O que é HTTP e sobre REST.

Agora é simples, no controller temos a rota users e a requisição POST, onde vamos receber um createUserDto, chamar o método create do usersService para criar um novo registro.

Obs: Por padrão a aplicação é criada utilizando a porta 3000, você pode alterar no arquivo main.ts.

Para testar utilizamos o insomnia, fizemos uma requisição POST para http://localhost:3000/users passando o JSON com as propriedades nome e idade (que definimos no CreateUserDto), com isso tivemos o retorno que o registro foi salvo e possui o id: 1. Ótimo, nossa rota para criar usuários está funcionando corretamente.

Atualizando um usuário

Nest.js - Fundamentos
Curso Nest.js - Fundamentos
Conhecer o curso

Para atualizar um registro, vamos utilizar o verbo PATCH, veja que há um método em nosso controller criado pelo Nest CLI, vamos usá-lo.

@Patch(':id')
update(@Param('id') id: number, @Body() updateUserDto: UpdateUserDto) {
  return this.usersService.update(id, updateUserDto);
}

Neste caso temos na rota o id, ou seja, precisamos passar na url o id do registro que queremos atualizar, para este exemplo, ficará: http://localhost:3000/users/1, desta forma vamos atualizar o usuário de id igual a 1.

O arquivo UpdateUserDto está estendendo parte do CreateUserDto, portanto, neste momento não precisamos alterar este arquivo, pois vamos atualizar o nome e/ou idade de qualquer forma.

Por fim, precisamos criar o método em nosso service que irá atualizar efetivamente o usuário:

update(id: number, updateUserDto: UpdateUserDto) {
    return this.userRepository.update(id, updateUserDto);
}

Seguindo a ideia do create, neste momento usamos o método update, passamos o id do registro a ser atualizado e o dto com as novas informações.

Perfeito, temos o retorno 200 OK e a informação que um registro foi alterado.

Criando lista e buscando usuário único

Mas fica a pergunta, como podemos ver efetivamente o registro alterado? Podemos criar uma lista ou buscar um único usuário de forma bem prática. Ao criar os arquivos com o Nest CLI, no controller há as seguintes rotas:

@Get()
findAll() {
  return this.usersService.findAll();
}

@Get(':id')
findOne(@Param('id') id: number) {
  return this.usersService.findOne(id);
}

Perceba que são duas rotas utilizando o verbo HTTP GET, onde na primeira nós vamos obter a lista de registros, e na outra passamos o id para obter este único registro. Então vamos criar essas buscas em nosso service:

findAll() {
  return this.userRepository.find();
}

findOne(id: number) {
  return this.userRepository.findOneBy({ id: id });
}

Agora vamos criar outro registro com as mesmas informações do primeiro só para termos mais de um usuário em nossa base, e então verificar a busca referente a lista, e então, um único registro da forma correta.

Usuário de id igual a 2 criado com sucesso.

Lista de usuários conforme o espero, repare que o registro de id igual a 1 foi atualizado com sucesso.

Por fim, vamos buscar um registro pelo seu id único:

Utilizando o verbo HTTP GET, passamos o id igual a 1 na url e como esperado o retorno foi do único usuário de id igual a 1.

Portanto, criamos um usuário, atualizamos, podemos listar todos os usuário ou buscar por um único registro, agora só está faltando um recurso de nosso CRUD, o delete, então vamos ver como podemos remover um registro.

Removendo um usuário

Para criar nossa função de remover usuários basta seguirmos a lógica das ações anteriores, com isto vamos utilizar o método remove do service da nossa aplicação:

remove(id: number) {
  return this.userRepository.delete(id);
}

Podemos utilizar o repository com o método delete passando apenas o id do registro que queremos excluir e agora chamar o método remove na camada de controller.

@Delete(':id')
remove(@Param('id') id: number) {
  return this.usersService.remove(id);
}

Lembrando que neste caso utilizamos o verbo HTTP DELETE e passamos o id como parâmetro.

Vamos testar!

De acordo com a imagem acima, excluímos com sucesso o registro de id igual a 1, ao buscar a lista de usuários, portanto, vamos obter somente o usuário de id igual a 2:

Conclusão

Neste artigo aprendemos passo a passo a criar um CRUD com NestJS, utilizando ferramentas como o Nest CLI, vimos por cima o uso do TypeORM e como trabalhamos com as camadas de entidade, controller, service e repository. O NestJS nos permite criar sistemas Web e APIs de forma prática e robusta, como veremos nos próximos artigos sobre serialização, validação, autenticação e outros recursos que podemos utilizar com este framework.

Ah, antes que me esqueça, você pode acessar o código da aplicação desenvolvida neste artigo através do repositório no GitHub 😁

Nesse artigo vimos vários recursos do NestJS, mas isso é apenas o começo, existem muitos outros recursos e funcionalidades disponíveis neste incrível framework, caso queira aprender mais sobre NestJS saiba que aqui na TreinaWeb nós temos o curso NestJS - Fundamentos que possui 02h07 de videos e um total de 18 exercícios. Conheça também nossos outros cursos de TypeScript.

Veja quais são os tópicos abordados durante o curso de NestJS - Fundamentos:

  • Conhecendo a estrutura;
  • Utilizando Nest CLI;
  • Entendendo Rotas, Controllers e Views;
  • Conexão com banco de dados;
  • Usando TypeORM;
  • Template Engine.

Autor(a) do artigo

Wesley Gado
Wesley Gado

Formado em Análise e Desenvolvimento de Sistemas pelo Instituto Federal de São Paulo, atuou em projetos como desenvolvedor Front-End. Nas horas vagas grava Podcast e arrisca uns três acordes no violão.

Todos os artigos

Artigos relacionados Ver todos