Coisas simples para você não perguntar para seu sênior - #1
Como configurar um Postgres no Nest
Por que estou fazendo esse projeto
Recentemente, saí de uma empresa onde qualquer dúvida básica que eu tinha era motivo de pavor para mim. Sabia que algumas pessoas achariam minhas dúvidas um pouco bestas para alguém da minha senioridade. Pois bem, para que nem eu e nem você, que não chegou lá na sua senioridade ou simplesmente precisa pegar alguns exemplos simples do dia a dia para seguir, irei trazer nessa série de postagens algumas dicas simples de coisas que a gente como desenvolvedor sempre acaba buscando, afim de que eu aprenda mais e que eu consiga fazer o que algumas pessoas não fizeram comigo, ajudar um amigo com uma dúvida!
O "Coisas simples para você não perguntar para seu sênior" de hoje será a configuração de um Postgres em um projeto de Nest. O Nest está sendo bastante utilizado para alguns projetos de backend, e apesar da documentação do Nest ser bem completa, é sempre bom termos um ou outro exemplo para observarmos e utilizar da melhor forma possível.
Criando banco de testes com o Docker Compose
Para nosso teste, utilizaremos de um banco local criado no Docker, então vale lembrar que pra esse tutorial você precisa ter o Docker instalado e configurado na sua máquina
Criaremos um arquivo dentro do nosso projeto Nest, fora da nossa pastinha de /src, chamado de docker.compose.yml. Esse arquivo servirá como um ordenador ao docker para fazer a criação de um container e das suas especificações de maneira mais fácil do que se fizessemos isso na mão.
O arquivo será assim:
version: '3.8'
services:
db:
image: postgres
restart: always
environment:
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=admin
- POSTGRES_DB=posts
#usaremos esse nome de DB apenas para exemplificar
ports:
- '5432:5432'
volumes:
- db:/var/lib/postgresql/data
volumes:
db:
driver: local
Após esse arquivo ter sido criado e nosso Docker estiver de pé, podemos rodar um comando para subir esse banco.
Note que, caso o comando não funcionar, pode ser que você tenha que instalar o docker-compose. Também é algo fácil de você pesquisar, confio em você 😊
O comando é esse:
docker-compose up -d
Após isso, seu banco deve estar de pé e pronto para ser utilizado.
Instalando Pacotes
Para começar, precisamos instalar alguns pacotes. Abra o terminal e digite o seguinte comando:
Esse comando vai instalar os plugins do typeorm e do postgres:
npm i --save @nestjs/typeorm typeorm pg
Já esse comando abaixo irá instalar algumas configs do Nest:
npm i --save @nestjs/config
Configurando TypeORM
Primeiramente, para utilizarmos de uma maneira na qual usaríamos em um projeto na vida real, criaremos um arquivo, também na raiz do projeto, chamado .env, para que nele fiquem as variáveis de ambiente para configurarmos o banco
Esse arquivo será dessa maneira:
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_USER=admin
POSTGRES_PASSWORD=admin
POSTGRES_DATABASE=posts
PORT=3000
MODE=DEV
RUN_MIGRATIONS=true
Após isso, configuraremos nosso projeto para capturar nossas variáveis de ambiente, fazendo com que nosso app.module.ts esteja dessa maneira:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [ConfigModule.forRoot()],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Após isso, criaremos um novo arquivo que guardará nossas informações para configurar o banco de dados quando rodarmos nosso projeto. Esse arquivo se chamará data-source, veja como ele ficará:
//src/db/data-source.ts
import { DataSource, DataSourceOptions } from 'typeorm';
import * as dotenv from 'dotenv';
dotenv.config();
export const dataSourceOptions: DataSourceOptions = {
type: 'postgres',
host: process.env.POSTGRES_HOST,
port: parseInt(process.env.POSTGRES_PORT),
username: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
database: process.env.POSTGRES_DATABASE,
entities: ['dist/**/*.entity{.ts,.js}'],
migrationsTableName: 'migration',
migrations: ['dist/db/migrations/*{.ts,.js}'],
migrationsRun: true,
};
const dataSource = new DataSource(dataSourceOptions);
export default dataSource;
O TypeOrm é um ORM (Object Relational Mapping) que permite a comunicação entre o banco de dados e o Nest. Para configurá-lo, precisamos editar o arquivo app.module.ts
e adicionar o TypeOrmModule ao array de imports, juntamente com a configuração do datasource que fizemos acima. Olha só como ficou nosso App Module:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { dataSourceOptions } from './db/data-source';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
TypeOrmModule.forRoot(dataSourceOptions),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Configurando as migrations
Você viu que no nosso arquivo de configuração de data source nós colocamos algumas informações relacionadas a Migrations?
Mas que raio é isso?
As migrations nada mais são do que queries que funcionam como uma máquina do tempo do que acontece no nosso banco de dados. Isso mesmo, não é zueira. Nas migrations, eu consigo criar novas tabelas, editar alguma propriedade de uma tabela existente, enfim, manipular o quanto eu precisar o banco de dados de forma segura e rastreável. E o TypeORM consegue nos ajudar nisso, gerando automaticamente as nossas migrations através de alguns comandos. Vamos ver na prática como isso funciona?
Primeiramente, para nossa primeira entidade do banco, iremos criar uma classe simples dentro do nosso projeto
// src/entities/post.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity({ name: 'posts' })
export class PostEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ type: 'varchar', length: 300 })
title: string;
}
Show! Temos a nossa primeira tabela, mas se formos olhar lá no banco de dados, ainda não teremos nenhuma tabela. Para isso precisamos colocar alguns novos comandos lá no nosso package.json:
"typeorm": "npm run build && npx typeorm -d dist/db/data-source.js ",
"migration:generate": "npm run typeorm -- migration:generate",
"migration:run": "npm run typeorm -- migration:run",
"migration:revert": "npm run typeorm -- migration:revert"
O primeiro comando, irá ligar o TypeORM no nosso banco, com as configurações que fizemos lá no data source.
Já o migration:generate vai ser o cara que faz a mágica de ver o que no nosso código mudou e transforma isso em um arquivo que virará uma query para executarmos no banco
O migration:run será nosso DeLorean, aquele que vai rodar a query que geramos ou outras que tenhamos na nossa pasta de migrations..
O migration:revert será utilizado caso nós tenhamos que voltar no tempo caso alguma coisa dê errado.
Como já temos nossos scripts prontos, podemos gerar nossa primeira migration, rodando o seguinte comando:
npm run migration:generate -- src/db/migrations/create-table-post
Agora para que consigamos que isso vá para nosso banco de dados, usaremos esse comando:
npm run migration:run
Se você olhar lá no seu banco de dados agora, vai ver que demais, a nossa entidade está lá no banco da maneira que setamos dentro do nosso Nest!
Conclusão
Pronto! Agora você já configurou um banco de dados Postgres no Nest usando o TypeOrm. A partir daqui, você pode começar a criar suas entidades e usar o TypeOrm para se comunicar com o banco de dados de maneira mais fácil e feliz!
https://docs.nestjs.com/techniques/database
https://docs.nestjs.com/techniques/configuration
https://docs.nestjs.com/techniques/database#migrations
https://typeorm.io/migrations#creating-a-new-migration
https://www.youtube.com/watch?v=Ty_Zs2w3KYo&t=1261s&ab_channel=AmitavRoy