Este é um projeto de API de gerenciamento de tarefas (Todo) construído com Node.js, Express, PostgreSQL e Drizzle ORM. A API permite criar, ler, atualizar e excluir tarefas, além de gerenciar usuários e autenticação.
É possível configurar o projeto localmente de duas formas:
- Configurar o projeto com Docker
- Configurar o projeto nativa e localmente
Certifique-se de ter o Docker e o Docker Compose instalados em sua máquina para a configuração com Docker.
Se você estiver no Linux:
Se você estiver no Windows:
- Docker (o comando
docker-composejá vem instalado no pacote do Docker para Windows)
-
Clone o repositório:
git clone https://github.com/reszkojr/todo-express cd todo-express -
Inicie os containers Docker:
Apenas para Windows: certifique-se de que a interface do Docker esteja aberta para que o daemon do Docker esteja iniciado.
docker-compose up --buildO servidor estará disponível em http://localhost:3000 quando você ver a seguinte mensagem nos logs do Docker:
> todo-express@1.0.0 dev /app
> ts-node src/app.ts
Server running on port 3000
Swagger docs available at http://localhost:3000/api-docsO docker-compose.yaml define os serviços necessários para a aplicação, como o banco de dados PostgreSQL e o Express.js em Node.
O Dockerfile contém as instruções para criar a imagem Docker da aplicação Node, incluindo a instalação das dependências e a definição do comando de inicialização.
Rodando o comando docker-compose up --build, é exposta a porta 5432, que roda o banco do PostgreSQL e a porta 3000, que roda o backend em si.
Para a configuração local, certifique-se de ter o Node.js e o PostgreSQL instalados.
-
Clone o repositório:
git clone https://github.com/reszkojr/todo-express cd todo-express -
Instale as dependências:
pnpm install
-
Configure o arquivo
.env:Crie um arquivo
.env(ou renomeie o arquivo.env.examplepara.env) na raiz do projeto e adicione as seguintes variáveis de ambiente:DATABASE_URL=postgresql://postgres:pgpassword@localhost:5432/todos DATABASE_URL_TEST=postgresql://postgres:pgpassword@localhost:5433/todos PORT=3000 JWT_SECRET_KEY=sua_chave_secreta_jwt JWT_REFRESH_SECRET_KEY=sua_chave_secreta_refresh_jwt
-
Inicie o PostgreSQL:
Certifique-se de que o PostgreSQL está em execução e que você criou os bancos de dados
todos. -
Crie as migrações do banco de dados:
pnpm run db:generate
-
Execute as migrações do banco de dados:
pnpm run db:migrate
-
Inicie o servidor:
pnpm run dev
O servidor estará disponível em
http://localhost:3000.
As tabelas do banco de dados são iniciadas automaticamente com o Drizzle quando os containers Docker são iniciados.
Ao realizar a build da imagem, o Drizzle espera o banco do PostgreSQL iniciar para gerar as migrações e, então, aplicá-las ao banco. Nesse momento, são criadas as tabelas user e todo.
Para testar a API em um ambiente Docker, primeiro, certifique-se de que ela está em execução. Em seguida, execute o seguinte comando para rodar os testes:
sudo docker-compose exec -it backend pnpm run testEste comando irá executar os testes definidos no projeto dentro do container Docker do backend.
Para testar a API em um ambiente local, primeiro, certifique-se de que ela está em execução. Em seguida,
crie um novo servidor de banco de dados na porta 5433 ou modifique o arquivo .env para que a URL do banco de teste utilize a porta do seu banco de teste.
É importante que ele esteja vazio, para não haver conflitos nos testes.
Com tudo configurado, execute o seguinte comando para rodar os testes:
pnpm run testA documentação da API é gerada automaticamente usando Swagger. É possível acessa-la em http://localhost:3000/api-docs/.
-
Registrar Usuário
- POST
/api/register - Corpo da Requisição:
{ "username": "novo_usuario", "email": "novo_usuario@example.com", "password": "senha123" }
- POST
-
Login de Usuário
- POST
/api/login - Corpo da Requisição:
{ "email": "usuario@example.com", "password": "senha123" }
- POST
-
Token Refresh
- POST
/api/refresh-token - Corpo da Requisição:
{ "refreshToken": "seu_refresh_token" }
- POST
-
Obter Todas as Tarefas
-
GET
/api/todosExemplo de comando
curl:curl -X GET http://localhost:3000/api/todos
-
-
Obter Tarefa por ID
-
GET
/api/todos/:idExemplo de comando
curl:curl -X GET http://localhost:3000/api/todos/1
-
-
Criar Nova Tarefa
- POST
/api/todos - Corpo da Requisição:
{ "title": "Nova Tarefa", "description": "Descrição da nova tarefa", "status": "pending" }
- POST
-
Atualizar Tarefa
- PUT
/api/todos/:id - Corpo da Requisição:
{ "title": "Tarefa Atualizada", "description": "Descrição atualizada", "status": "in progress" }
- PUT
-
Deletar Tarefa
- DELETE
/api/todos/:id
- DELETE
- Abra o Bruno.
- Clique em "Import Collection".
- Selecione o arquivo
todo-bruno-api-client.json. - Configure a variável
hostparahttp://localhost:3000.
- Abra o Postman.
- Clique em "Import".
- Selecione o arquivo
todo-postman-api-client.json. - Configure a variável
hostparahttp://localhost:3000.
- src/: Contém o código-fonte do projeto.
- controllers/: Controladores que contêm a lógica das rotas.
- db/: Configuração do banco de dados e esquemas.
- middleware/: Middlewares para autenticação e outras funcionalidades.
- routes/: Definição das rotas da API.
- utils/: Utilitários e funções auxiliares.
- .env: Arquivo de configuração de variáveis de ambiente.
- docker-compose.yaml: Configuração do Docker Compose.
- package.json: Dependências e scripts do projeto.
É possível consumir a API usando ferramentas como Postman ou Bruno utilizando as configurações passadas anteriormente ou utilizando o curl.
Aqui estão alguns exemplos utilizando o curl para testar as rotas:
curl -X GET http://localhost:3000/api/todoscurl -X GET http://localhost:3000/api/todos/1curl -X POST http://localhost:3000/api/todos \
-H "Content-Type: application/json" \
-d '{
"title": "Nova Tarefa",
"description": "Descrição da nova tarefa",
"status": "pending"
}'curl -X PUT http://localhost:3000/api/todos/1 \
-H "Content-Type: application/json" \
-d '{
"title": "Tarefa Atualizada",
"description": "Descrição atualizada",
"status": "in progress"
}'curl -X DELETE http://localhost:3000/api/todos/1Escolhi o Drizzle para simplificar a interação com o banco. Ele, por ser uma ORM, oferece uma camada de abstração que facilita muito a definição de esquemas, migrações e consultas, reduzindo a quantidade de código repetitivo, minimizando erros comuns em operações de banco de dados e aumentando muito a segurança das operações do banco.
Optei pelo pnpm como gerenciador de pacotes devido à velocidade. Ele é muito mais rápido que o npm no que tange a instalação de pacotes e muio mais eficiente para gerenciar o tamanho do node_modules, pois todos eles são armazenados em uma pasta geral e, em projetos específicos, caso o pacote já exista, só é criado um symlink da pasta geral para o node_modules do projeto.
A utilização do TypeScript foi uma escolha para aumentar a produtividade e conseguir desenvolver o projeto com mais rapidez e deixá-lo mais "manutenível", pois certamente é uma linguagem extremamente importante de se utilizar em projetos de larga escala por conta de sua tipagem. O Intellisense do Typescript junto a um linter tornam o desenvolvimento muito mais fluido e gostosinho.
O Docker foi escolhido para isolar cada módulo da aplicação, como o banco de dados e o próprio back-end, a fim de se manter organização no meu espaço de trabalho pessoal — pois tenho mais de um PostgreSQL rodando na minha máquina — e para facilitar a configuração do projeto por pessoas de fora.
Optei pelo ts-jest em vez do jest normal para facilitar a integração com o TypeScript e manter a consistência com o projeto pois permite que os testes sejam escritos diretamente em TypeScript.