Este guia apresenta o passo a passo para construir uma API de lista de tarefas (TO-DO) usando Nest.js, Swagger para documentação, integração com MySQL e a implementação de Docker para facilitar a configuração e execução.
Passo 1: Configurando o Ambiente
Antes de iniciarmos, certifique-se de ter o Node.js e o npm instalados. Em seguida, instale o Nest.js globalmente utilizando o seguinte comando:
npm install -g @nestjs/cli
Agora, crie um novo projeto Nest.js:
nest new nest-todo-api
cd nest-todo-api
Vamos remover os arquivos abaixo que não serão necessários.
rm ./src/app.controller.spec.ts
rm ./src/app.controller.ts
rm ./src/app.service.ts
Passo 2: Instalando Dependências
Instale as dependências necessárias para a nossa API:
npm install @nestjs/swagger swagger-ui-express mysql2 typeorm @nestjs/typeorm
Passo 3: Criando o Módulo, Controller, Service e a Entidade para Tarefas
Agora, vamos criar um módulo, controller, service para as tarefas e uma entidade para representar a tabela no banco de dados:
nest generate module task
nest generate controller task
nest generate service task
nest generate class task/task.entity
Passo 4: Configurando o Banco de Dados e Entidade
Vamos configurar a conexão com o MySQL utilizando o TypeORM. No arquivo src/app.module.ts, adicione o seguinte trecho para configurar o banco de dados:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TaskModule } from './task/task.module';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: 'mysql',
port: 3306,
username: 'seu_usuario',
password: 'sua_senha',
database: 'todo_db',
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: true,
}),
TaskModule,
],
})
export class AppModule {}
No arquivo task.entity.ts, adicione a seguinte definição de entidade:
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity()
export class Task {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@Column({ nullable: true })
description: string;
}
No arquivo task.module.ts, adicione a seguinte definição:
import { Module } from '@nestjs/common';
import { TaskController } from './task.controller';
import { TaskService } from './task.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Task } from './task.entity/task.entity';
@Module({
imports: [TypeOrmModule.forFeature([Task])],
controllers: [TaskController],
providers: [TaskService]
})
export class TaskModule {}
Passo 5: Implementando Operações CRUD
O service é responsável por interagir com o banco de dados para executar operações relacionadas às tarefas. Adicione a seguinte implementação em task.service.ts:
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Task } from './task.entity/task.entity';
@Injectable()
export class TaskService {
constructor(
@InjectRepository(Task)
private taskRepository: Repository<Task>,
) {}
async findAll(): Promise<Task[]> {
return await this.taskRepository.find();
}
async create(task: Task): Promise<Task> {
return await this.taskRepository.save(task);
}
async update(id: number, updatedTask: Task): Promise<Task> {
const existingTask = await this.taskRepository.findOne(id);
if (!existingTask) {
throw new Error('Tarefa não encontrada');
}
existingTask.title = updatedTask.title;
existingTask.description = updatedTask.description;
return await this.taskRepository.save(existingTask);
}
async remove(id: number): Promise<void> {
const existingTask = await this.taskRepository.findOne(id);
if (!existingTask) {
throw new Error('Tarefa não encontrada');
}
await this.taskRepository.remove(existingTask);
}
}
No arquivo task.controller.ts, implemente as operações CRUD:
import { Controller, Get, Post, Body, Put, Param, Delete } from '@nestjs/common';
import { TaskService } from './task.service';
import { Task } from './task.entity/task.entity';
@Controller('tasks')
export class TaskController {
constructor(private readonly taskService: TaskService) {}
@Get()
findAll(): Promise<Task[]> {
return this.taskService.findAll();
}
@Post()
create(@Body() task: Task): Promise<Task> {
return this.taskService.create(task);
}
@Put(':id')
update(@Param('id') id: string, @Body() task: Task): Promise<Task> {
return this.taskService.update(+id, task);
}
@Delete(':id')
remove(@Param('id') id: string): Promise<void> {
return this.taskService.remove(+id);
}
}
Passo 6: Integrando Swagger
No arquivo main.ts, adicione as configurações do Swagger:
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const config = new DocumentBuilder()
.setTitle('API TO-DO Nest.js')
.setDescription('Documentação da API de TO-DO')
.setVersion('1.0.0')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
await app.listen(3000);
}
bootstrap();
Passo 7: Configurando Dockerfile e Compose
Crie o arquivo Dockerfile na raiz do projeto e adicione as configurações:
FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "run", "start"]
Crie o arquivo docker-compose.yml na raiz do projeto e adicione as configurações:
version: '3'
services:
# MySQL Service
mysql:
image: mysql:latest
environment:
MYSQL_ROOT_PASSWORD: root_senha
MYSQL_DATABASE: todo_db
MYSQL_USER: seu_usuario
MYSQL_PASSWORD: sua_senha
ports:
- "3306:3306"
networks:
- app-network
# Nest.js App Service
nest-app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
depends_on:
- mysql
networks:
- app-network
networks:
app-network:
driver: bridge
Passo 8: Executando o Projeto
Execute o comando abaixo:
docker compose up
Acesse o Swagger em http://localhost:3000/api para visualizar e testar as operações CRUD da sua API TO-DO.
O projeto deste post está no meu github link.