CRUD com NestJS usando Postgres

Estevam Souza
13 min readOct 9, 2022

--

O NestJS é um framework back-end baseado no popular framework front-end Angular como sua inspiração, o seu uso é na linguagem Typescript. E como no Angular traz um CLI para construção de modules, controllers, services, guards, e muito mais, nos poupando de escrever aquelas linhas de códigos repetitivas. No entanto, suas inspirações não acabam aí, seus controllers e modo de mapear as rotas se parecem muito com o framework back-end com linguagem Java, o Spring.

O framework back-end NestJS nos ajuda no desenvolvimento de aplicações bem mais eficientes utilizando o Node.js. Por padrão o NestJS usa o TypeScript e é bem semelhante a sintaxe do Angular, e o mais curioso que o NestJS usa o “express” internamente como framework web.

A progressive Node.js framework for building efficient, reliable and scalable server-side applications.

Os requisitos de nossa API

A ideia é que ao final dessa série tenhamos um projeto com as seguintes funcionalidades:

  • Criação de conta para usuários externos
  • Criação de conta para usuários Administradores
  • Autenticação e Autorização
  • Envio de emails para confirmação de cadastro
  • Envio de emails para recuperação de senha
  • Busca de usuários com filtros e paginação
  • Busca de dados de um usuário específico
  • Bloquear o acesso de um usuário
  • Manter um log do que acontece no servidor

Nossa API utilizará o PostgreSQL como banco de dados e usaremos o Docker para facilitar nossa vida de desenvolvedores. Nessa primeira parte do tutorial vamos tratar da configuração do ambiente e criação do nosso primeiro endpoint, “Criação de conta para usuários Administradores”.

Instalação do NestJS

A primeira coisa que você precisa ter instalada na sua máquina é, claro, o Node.js (e junto com ele, o npm). Para isso basta seguir as instruções no site.

É necessário instalar o NestJS de forma global.

Com o Node e o npm instalados, vamos começar a instalar a CLI (Command Line Interface ) do NestJS. Para isso, basta executar o seguinte comando no terminal:

$ npm i -g @nestjs/cli

Caso tenha algum problema durante a instalação, certifique-se de que tem as permissões necessárias, ou utilize o sudo se estiver no Linux e for necessário. Com o pacote da linha de comando instalado, podemos utilizá-lo para criar nosso projeto:

$ nest new nestjs-pgsql-api

Utilizando a CLI do Nest para criar um projeto, escolha o NPM, YARN ou PNPM com gerenciador de pacote.

nest new project-name

Após a execução deste comando, basta selecionar o npm como gerenciador de dependências. Caso prefira poderá utiliar o yarn, entretanto durante o restante deste tutorial utilizaremos o npm. Quando o comando finalizar de gerar a base de seu projeto, podemos entrar dentro do diretório:

$ cd nestjs-pgsql-api

Abrindo o projeto, você se depara com essa estrutura de pastas:

Estrutura de pastas do NestJS

Podemos observar entre os arquivos gerados a pasta src, onde ficará nosso código e a pasta test para arquivos de teste. Você pode já rodar o seguinte comando para ter certeza de que tudo está ok:

$ npm run start:dev

No browser ou qualquer programa de consumo de API(Postman, Insomnia), faça uma requisição GET para a URL http://localhost:3000. Teremos o nosso ‘Hello World’, para modificar isso, vamos no arquivo src/app.service.ts, modificamos o retorno para trazer a versão de nossa API.

import { Injectable } from '@nestjs/common';@Injectable()
export class AppService {
getHello(): any {
return {
version: '1.0.0',
description: 'CRUD com NestJS e NestJSX'
};
}
}

No browser ou qualquer programa de consumo de API(Postman, Insomnia), faça uma requisição GET para a URL http://localhost:3000. Teremos o nosso ‘Hello World’, para modificar isso, vamos no arquivo src/app.service.ts, modificamos o retorno para trazer a versão de nossa API.

import { Injectable } from '@nestjs/common';@Injectable()
export class AppService {
getHello(): any {
return {
version: '1.0.0',
description: 'CRUD com NestJS e NestJSX'
};
}
}

Fazemos de novo a requisição GET para http://localhost:3000. Observamos que assim como o Angular a injeção de dependência é feita com decorators.

Para continuar vamos instalar as dependências do TypeORM e NestJSX.

npm i --save pg typeorm @nestjs/typeorm @nestjsx/crud @nestjsx/crud-typeorm class-transformer @nestjs/swagger

Importamos no nosso app.module.ts o item que vai observar as modificações e criação da nossa classe.

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm'
import { ConsumerModule } from './consumer/consumer.module';
@Module({
imports: [TypeOrmModule.forRoot()],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

Criamos na raiz do projeto o aquivo ormconfig.json para utilizar nosso banco, um JSON com a seguinte configuração.

{
"type": "postgres",
"host": "localhost",
"port": 5432,
"username": "‹seu usuario›",
"password": "‹sua senha›",
"database": "‹seu banco›",
"entities": ["dist/**/*.entity.js"],
"synchronize": true,
"logging": true
}

Agora vamos criar nossa classe, utilizando a CLI do Nest — apesar desse comando não nos poupar tanto de escrever — passamos uma flag para não escrever o teste, pois não utilizaremos teste nesse tutorial.

nest g class model/consumer.entity --no-spec

Com nossa classe passamos os decorators do TypeORM para a criação da tabela na nossa base.

import { Entity, Column, PrimaryGeneratedColumn} from 'typeorm'@Entity()
export class Consumer{
@PrimaryGeneratedColumn('uuid')
id: string
@Column({length: 65})
name: string
@Column({length: 65})
email: string
}

Já com nossa classe, vamos criar o module, com o comando.

nest g module consumer

Vamos abrir o arquivo do nosso module, no caso consumer.module.ts dentro da pasta consumer, para implementar mais um item do Nest para o TypeORM. Assim, injeta a nossa classe para que nós possamos conseguir utilizar o seu repositório que virá pronto.

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Consumer } from 'src/model/consumer.entity';
import { ConsumerController} from './consumer.controller';
import { ConsumerService} from './consumer.service';
@Module({
imports: [ TypeOrmModule.forFeature([Consumer])]
})
export class ConsumerModule {}

controllers e providers, não precisa se preocupar, pois se utilizar o CLI ele será escrito automaticamente no module.

Mais um comando do CLI, para criar nosso service, onde ficarão as funções que intermediarão com nosso repositório.

nest g service consumer --no-spec

Dentro da pasta consumer, vamos encontrar nosso consumer.service.ts.

Utilizando o @InjectRepository já temos o nosso repositório pronto com as principais funções e um pouco mais. Estendendo da classe TypeOrmCrudService, temos as funções para intermediar com nosso repositório, colocando todas as funções no service para o essencial de um CRUD.

import { Injectable } from '@nestjs/common';
import { Consumer } from 'src/model/consumer.entity';
import { TypeOrmCrudService } from '@nestjsx/crud-typeorm'
import { InjectRepository } from '@nestjs/typeorm';
@Injectable()
export class ConsumerService extends TypeOrmCrudService<Consumer>{
constructor(@InjectRepository(Consumer) repo) {
super(repo)
}
}

Agora a última coisa para funcionar nossa API, o nosso controller que é criado com a CLI com o seguinte comando.

nest g controller --no-spec

De novo na pasta consumer, encontramos o consumer.controller.ts.

Eu gosto de deixar os recursos no plural, por isso acrescentei um ‘s’ em ‘consumer’ no decorator @controller. Agora siga com a atenção no construtor, a variável service, deve se chamar service, se não ocorrera um erro de undefined nas funções do service. Para finalizar, use o decorator @Crud com a configuração passada. Esse decorator que trará todas as rotas assim como mostrado na documentação, para utilizar todas as funções essenciais de um CRUD, e mais uma rota que permite o cadastro de vários registros, no nosso caso de vários consumers numa requisição só.

import { Controller } from "@nestjs/common";
import { Crud } from '@nestjsx/crud'
import { Consumer } from "src/model/consumer.entity";
import { ConsumerService } from "./consumer.service";
@Crud({
model: {
type: Consumer
},
params: {
id: {
field: 'id',
type: 'uuid',
primary: true
}
}
})
@Controller('consumers')
export class ConsumerController {
constructor(public service: ConsumerService) {}
}

Configuração do PostgreSQL com o Docker

Utilizaremos o Docker em conjunto com o Docker Compose para configuração do nosso ambiente. Para manter o foco deste tutorial, não abordarei como instalar e configurar estas ferramentas. Instruções podem ser encontradas nas documentações oficiais ou em diversos tutoriais na internet. Caso não deseje utilizar o Docker para configuração do ambiente pode instalar o PostgreSQL em sua máquina e configurar um usuário e senha para acesso. O importante é você ter acesso a um banco de dados Postgre.

Vamos adicionar um arquivo docker-compose.yml na raiz de nosso projeto com as configurações de nossos containers.

docker-compose.yml

Você irá notar que também adicionei um container rodando o adminer. Adminer é um sistema de gerenciamento de banco de dados (SGBD) escrito em PHP, bem leve e com todas as funcionalidades que precisaremos neste tutorial.

Para testar se está tudo ok, vamos subir nossos containers:

$ docker-compose up -d

O comando pode demorar um pouco para executar caso ainda não tenha as imagens na sua máquina. Quando ele finalizar, você poderá acessar o adminer em http://localhost:8080/. Selecione o sistema PostgreSQL, informe o servidor, que no caso será o nome que demos ao nosso container: pgsql. Informe o nome de usuário e senha, pguser e pgpassword respectivamente. Caso tenha substituído estes parâmetros em seu arquivo docker-compose.yml certifique-se de substituí-los aqui também. Clique em Entrar.

Se tudo estiver correto você será redirecionado para a página de gerenciamento de banco de dados. Nela, clique em “Criar Base de dados” e crie o banco de dados nestjs, que usaremos no decorrer deste tutorial.

Conectando com o Banco de Dados

Precisamos agora conectar nossa aplicação NestJS com o banco de dados que acabamos de criar. Para tal utilizaremos o TypeORM. Vamos então instalar os pacotes necessários:

$ npm i --save typeorm @nestjs/typeorm pg

Agora, antes de começarmos a escrever nosso código, vamos fazer uma pequena limpeza no nosso projeto, removendo alguns arquivos que não serão utilizados.

  • Podemos apagar a pasta test por completo
  • Remover app.controller.spec.ts em src
  • Remover app.controller.ts em src
  • Remover app.service.ts em src

Lembre-se também de remover os respectivos imports no arquivo app.module.ts:

Como deverá ficar sem app.module.ts

Sua estrutura de pastas deve ter ficado dessa forma:

Estrutura após remoção de arquivos

Agora dentro da pasta src vamos criar uma pasta configs e dentro dela vamos criar o arquivo typeorm.config.ts:

typeorm.config.ts

Vamos adicionar agora o módulo do TypeORM aos imports globais, no arquivo app.module.ts.

app.module.ts

Após isso, rode novamente o comando para executar o projeto:

$ npm run start:dev

Se tudo estiver ok o projeto deve inicializar normalmente. Caso ocorra algum erro verifique se seguiu corretamente os passos até o momento.

Criando nosso primeiro endpoint

Nosso primeiro endpoint será referente à criação de um usuário com privilégios de administrador. Para tal, primeiro vamos criar nosso módulo de usuários, o módulo do nosso sistema responsável por tratar todas as questões que envolvam os usuários. Para adicionar um novo módulo ao projeto, basta executar o seguinte comando:

$ nest g module users

O que este comando faz? Ele cria uma pasta no diretório src com o nome do módulo escolhido e dentro dela cria um arquivo de declaração do módulo, nesse caso com o nome user.module.ts, e já adiciona a dependência no arquivo app.module.ts.

Dentro da nova pasta users vamos criar o arquivo user.entity.ts. Este arquivo terá a declaração da estrutura do nosso Usuário e será com base nele que o TypeORM irá gerar a tabela no banco de dados.

user.entity.ts

Observe os campos createdAt e updatedAt. Esses campos serão preenchidos automaticamente pelo TypeORM com timestamp de quando o objeto foi criado/alterado.

Podemos agora executar o comando:

$ npm run start:dev

E quando o projeto terminar de compilar, podemos acessar o painel do Adminer e dentro do nosso banco de dados nestjs veremos que foi criada a tabela user com a estrutura que descrevemos no users.entity.ts.

Vale a pena investir muito tempo com Nest.js?

Não é Next.js. É Nest.js, um framework de desenvolvimento web que é uma das tecnologias que mais gostei de conhecer em 2020. Eu gosto muito de trabalhar criando webservices com expressjs, porém o problema de trabalhar com várias linguagens e frameworks é que você sempre vai sentir falta de algo que existia naquela outra tecnologia. No meu caso, eu sentia falta de criar APIS REST de um modo parecido com o que eu criava com Java EE e de trabalhar com banco de dados de forma parecida com o que eu trabalhava com Active Record.

O Nest.js foi criado por

Kamil Mysliwiec

e já tem mais de 30 mil estrelas no github. Para ter uma ideia do tamanho atual do framework, o expressjs, que já é um framework mais antigo e, inclusive, é usado pelo Nest.js, tem 50 mil estrelas.

A documentação nos traz diferentes formas de estruturar a aplicação com Nest. Apis Rest, microserviços, Graphql, Websockets, Standalone entre outras. É um framework muito versátil.

  1. Definição do controller na classe pai, em localhost a chamada a qualquer endpoint dessa classe terá o prefixo ‘/cats’.
  2. O decorator Get() nos diz que esse método aceitará o método HTTP do tipo Get.
  3. Por default, será retornado um JSON com status da requisição 200.
  4. Existe uma injeção de dependência no construtor da classe para injetar a classe AppService.

Modularização

Esse conceito vai soar bem familiar para aqueles utilizam Angular para o desenvolvimento do client-side de suas aplicações. No NestJS toda a aplicação é desenvolvida em forma de módulos. Desta forma, um controller só terá acesso a um service caso ambos estejam explicitamente registrados no mesmo módulo.

A modularização é uma boa prática no desenvolvimento de aplicações empresariais uma vez que permite uma visualização mais clara da ligação existente entre as partes que compõem a aplicação. Além disso, uma vez modularizada, é mais fácil separar a aplicação em partes menores, o que pode viabilizar a criação de microservices, caso seja necessário.

Documentação

Por último mas não menos importante, a documentação do NestJS é excelente e explica de maneira detalhada a utilização de boa parte dos recursos disponíveis no framework, o que torna sua adoção ainda mais simples.

Além disso, caso tenha alguma dúvida que não é esclarecida pelos docs, os mantedores do NestJS são bem receptivos, então é só detalhar o problema no GitHub que com certeza algum desenvolvedor mais experiente estará disposto a te ajudar.

Antes de entrar bem afundo no nestjs, vale a pena saber mais sobre o node

Na JSConf 2009 Européia, um programador jovem chamado Ryan Dahl, apresentou um projeto em que estava trabalhando. Este projeto era uma plataforma que combinava a máquina virtual JavaScript V8 da Google e um laço de eventos. O projeto apontava para uma direção diferente das outras plataformas em JavaScript que rodam no servidor: todos I/O primitivos são orientado a evento. Aproveitando o poder e a simplicidade do Javascript, isso tornou tarefas difíceis de escrever aplicações assíncronas em tarefas fáceis. Desde quando foi aplaudido de pé no final do seu discurso, o projeto de Dahl tem recebido uma popularidade e uma aprovação sem precedentes.”

Instalação

A instalação é bem simples. Se você estiver no Windows, basta baixar o instalador no site oficial e executá-lo. Caso você esteja no Linux, como eu, pode utilizar um gerenciador de pacotes de acordo com a sua distribuição. Como eu uso o Ubuntu, precisei rodar apenas o seguinte comando:

$ curl -fsSL https://deb.nodesource.com/setup_14.x | sudo -E bash -
$ sudo apt-get install -y nodejs$ npm -v
6.14.13

$ node -v
v14.17.1

Alô, mundo

Vamos começar com o exemplo mais básico de desenvolvimento. Para isso, utilize o seu editor de texto favorito (o meu é o Visual Studio Code) e crie um diretório chamado alomundo contendo um arquivo chamado index.js:

O arquivo index.js é um arquivo que contém um código Javascript (extensão .js). O Node.js será capaz de executar esse código através do seguinte comando (digite no terminal de sua preferência):

$ node index.jsAlô, mundo!

O que aconteceu? O Node executou o código Javascript no lado do servidor (na sua máquina, nesse caso). Esse detalhe é importante pois ao codificar no Node, você não poderá utilizar variáveis e funções que existem no lado do cliente (nos navegadores

// É uma ótima ferramenta para fazer o lado back-end do seu código que remete a validar e retornar informações de um banco de dados por exemplo.

Breve Resumo sobre o node e oque é uma api

Acima tem um vídeo que indicamos para que entenda oque é o node.

AQUI UM BREVE RESUMO DO SITE DO NODEBR :

“é uma plataforma construída sobre o motor JavaScript do Google Chrome para facilmente construir aplicações de rede rápidas e escaláveis. Node.js usa um modelo de I/O direcionada a evento não bloqueante que o torna leve e eficiente, ideal para aplicações em tempo real com troca intensa de dados através de dispositivos distribuídos.

Oque é uma api?

Recursos Necessários

  • Node.js — É indicado baixar a versão 10.13.0
  • npm — Normalmente já vem instalado com o node.js
  • postman ou insomnia para fazer requisições na api
  • Um editor de texto (Indicado vsCode)

Como verificar a versão ou se está instalado ?

node -v && npm -v

Se retornar algo como 10.3.0 está tudo certo.

Planejando uma api

Como em qualquer projeto profissional é necessário pensar na arquitetura do seu projeto, a melhor forma de fazer isso é se fazer algumas perguntas :

  • Qual o objetivo dessa api?
  • Quais dados serão salvos e requisitados dessa api?
  • Oque vai acessa-la?

Próximos conteúdos

O intuito deste post é esquentar as turbinas. O meu planejamento contempla os seguintes tutoriais.

1 . CRUD Básico Nest.js com Mongoose

2. CRUD Básico Nest.js com Postgresql

3. Separando a aplicação Nest em módulos

4. CRUD básico usando typescript.

5. Tratamento de erros e built-in exceptions

6. Autenticação e autorização com Nest.js

Quanto tempo você já passou para fazer um CRUD básico como esse? Para se aprofundar no NestJS, NestJSX, e TypeORM leiam suas documentações, assim poderão fazer mais que CRUDs básicos.

--

--