Sobre • Vitrine Dev • Tecnologias • Instalações • Funcionalidades • Deploy • Autor • Licença
🚀 Neste projeto, será desenvolvido uma aplicação para check-ins em academias, aplicando conceitos do SOLID, Design Patterns, Docker para iniciar o banco de dados, JWT e Refresh Token, RBAC e diversos outros conceitos. O objetivo é fornecer um template completo e bem estruturado para o desenvolvimento de APIs RESTful com Node.js, Docker e Prisma, proporcionando uma base sólida para criar aplicações web escaláveis e de alta qualidade.
A primeira parte do projeto inclui a configuração de variáveis de ambiente para bancos de dados MySQL, utilizando o arquivo .env e o Prisma como ORM. As variáveis de ambiente são usadas para armazenar informações confidenciais, como credenciais de banco de dados, e para configurar o projeto de acordo com o ambiente de desenvolvimento ou produção.
Na segunda parte, é apresentada a arquitetura do projeto, utilizando a biblioteca Vitest para testes e cobertura de testes. Isso inclui a instalação de várias dependências, a criação de arquivos de configuração e a adição de scripts no package.json para executar testes e outras tarefas relacionadas.
A aplicação possui testes unitários de integração e testes e2e e uma cobertura de testes de 100%. Além disso, utilizamos o GitHub Actions para executar os testes unitários de integração e e2e e verificar a cobertura de testes a cada push na branch main.
Por fim, são apresentadas algumas funcionalidades adicionais e bibliotecas utilizadas no projeto, como bcryptjs para criptografia de senhas e dayjs para manipulação de datas. Além disso, o projeto inclui uma lista detalhada de requisitos funcionais e não funcionais, bem como regras de negócio que orientam o desenvolvimento das funcionalidades da aplicação.
Dessa forma, este projeto oferece um ponto de partida sólido para o desenvolvimento de aplicações web, incluindo configurações e ferramentas para garantir a qualidade do código e a manutenção do projeto ao longo do tempo.
🪧 Vitrine.Dev | |
---|---|
✨ Nome | API Rest NodeJs com SOLID |
🏷️ Tecnologias | NodeJs, TypeScript, JavaScript, .ENV, Fastify, PrismaJs, Zod, MySql, Docker, Vitest, GitHub Actions, Swagger, EsLint, Insomnia e JSON Web Token. |
As seguintes ferramentas foram usadas na construção do projeto
# Create project nodejs with npm and -y to accept all default options
npm init -y
// Create scripts in package.json
"scripts": {
"dev": "set NODE_ENV=dev&& tsx watch src/server.ts", // Create script to run server in development mode
"build": "tsup src !src/**/*.spec.ts !src/**/test/**/* --out-dir build --minify --publicDir src/docs", // Create script to build server in production mode
"start": "set NODE_ENV=production&& node build/server.js", // Create script to run server in production mode
},
Create .gitignore
file
Create .npmrc
file with save-exact=true
to save exact version of dependencies
npm install dotenv # Install dotenv to use environment variables in NodeJs
Create .env
file with all environment variables and gitignore this file
Create .env.example
file with all environment variables and not gitignore this file
npm install -D @rocketseat/eslint-config # Install Rocketseat ESLint config
Create .eslintrc.json
file with all ESLint config
Create .eslintignore
file with all ESLint ignore files
npm install -D typescript # Install TypeScript
npm install -D @types/node # Install @types/node to use types in NodeJs
npm install -D tsx # Install tsx to use compiler TypeScript in NodeJs in development mode
npm install -D tsup # Install tsup to use compiler TypeScript in NodeJs in production mode
npm install zod # Install zod to use types in NodeJs and validate data
npx tsc --init # Create tsconfig.json
"target": "es2020", // Change TypeScript target to ES2020 in tsconfig.json
"baseUrl": "./", // Specify the base directory to resolve non-relative module names.
"paths": {
"@/*": [
"./src/*"
],
} // Specify path aliases to import files in tsconfig.json
npm install fastify # Install Fastify
npm install @fastify/jwt # Install @fastify/jwt to use JWT in Fastify
npm install @fastify/cookie # Install @fastify/cookie to use cookie in Fastify
npm install @fastify/swagger # Install @fastify/swagger to use Swagger in Fastify
npm install @fastify/swagger-ui # Install @fastify/swagger-ui to use Swagger UI in Fastify
Create fastify-jwt.d.ts
file in @types folder with all types of JWT in Fastify
import '@fastify/jwt'
declare module '@fastify/jwt' {
export interface FastifyJWT {
user: {
sub: string
}
}
}
Create JWT_SECRET
in .env and .env.example
# Auth token in development mode
JWT_SECRET="secret"
Create script fastifyJwt
in app.ts to use JWT in Fastify
app.register(fastifyJwt, {
secret: env.JWT_SECRET,
})
Create openapi.json
file to documentation open API 3.0.1, save src/docs
Instalando Docker https://docs.docker.com/get-docker/
# Command to run postgres image database without docker-compose. This image is from bitnami (https://hub.docker.com/r/bitnami/postgresql)
docker run --name api-solid-pg -e POSTGRESQL_USERNAME=docker -e POSTGRESQL_PASSWORD=docker -e POSTGRESQL_DATABASE=apisolid -p 5432:5432 bitnami/postgresql
# We don't use this command because we use docker-compose to run all images, this command is just to show how to run a single image
// Create scripts in package.json
"scripts": {
"start-docker": "docker-compose up -d", // Create script to run docker-compose in background
"stop-docker": "docker-compose stop" // Create script to stop docker-compose
},
Create docker-compose.yml
file with all docker-compose config
Create .dockerignore
file with all docker-compose ignore files
# Commands to use docker
docker ps # List all running containers
docker ps -a # List all containers
docker images # List all images
docker pull mysql # Pull mysql image database (if you want to use mysql)
docker pull postgres # Pull postgres image database (if you want to use postgres)
docker pull mariadb # Pull mariadb image database (if you want to use mariadb)
docker start <container_id or container_name> # <container_id> Start container with id | <container_name> Start container with name
docker stop <container_id or container_name> # <container_id> Stop container with id | <container_name> Stop container with name
docker pause <container_id or container_name> # <container_id> Pause container with id | <container_name> Pause container with name
docker unpause <container_id or container_name> # <container_id> Unpause container with id | <container_name> Unpause container with name
docker rm <container_id or container_name> # <container_id> Remove container with id | <container_name> Remove container with name
docker logs <container_id or container_name> # <container_id> Show logs of container with id | <container_name> Show logs of container with name
docker inspect <container_id or container_name> # <container_id> Show all information of container with id | <container_name> Show all information of container with name
docker-compose --version # Show docker-compose version
docker-compose up # Run docker-compose, show logs in terminal
docker-compose up -d # Run docker-compose in background, not show logs in terminal
docker-compose start # Start o docker-compose
docker-compose stop # Stop o docker-compose, not remove all data in database
docker-compose down # Stop and remove o docker-compose, obs remove all data in database
npm install prisma # Install Prisma
npm i prisma-erd-generator @mermaid-js/mermaid-cli # Install Prisma ERD generator
npm i @prisma/client # Install Prisma client
npx prisma init # Create prisma folder with prisma.schema and prisma folder
npx prisma migrate dev # Enter a name for the new migration: » created tab Habits
npx prisma studio # Open Prisma Studio in browser
npx prisma studio -b firefox -p 5173 # Open Prisma Studio in browser with specific port and browser
npx prisma generate # Generate diagram in prisma folder
npx prisma db seed # Seed database with data in prisma/seed.ts - Populate database with data for development
// Add generator in prisma.schema
generator erd {
provider = "prisma-erd-generator"
}
// Create scripts in package.json
"scripts": {
"studio": "npx prisma studio -b firefox -p 5173", // Create script to open Prisma Studio in browser with specific port and browser
"generate": "npx prisma generate", // Create script to generate diagram in prisma folder
"migrate": "npx prisma migrate dev", // Create script to migrate database
"seed": "npx prisma db seed" // Create script to seed database
},
Environment variables to databases mysql
Create DATABASE_URL
in .env and .env.example file with MySql
DATABASE_URL="mysql://USER:PASSWORD@HOST:PORT/DATABASE_NAME"
SHADOW_DATABASE_URL="mysql://OTHER_USER:PASSWORD@HOST:PORT/OTHER_DATABASE_NAME"
I used mysql, but you can use postgresql, mariadb, sqlite, sqlserver, mongodb, etc.
// Add datasource in prisma.schema to mysql database
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
shadowDatabaseUrl = env("SHADOW_DATABASE_URL")
}
// https://www.prisma.io/docs/concepts/components/prisma-migrate/shadow-database
// Exist provider that user cannot have access to create a database, to resolve this problem, you can use shadow database
npm install -D vitest # Install Vitest
npm install -D vite-tsconfig-paths # To vite understand tsconfig paths
npm install -D @vitest/coverage-c8 # Install coverage vitest
npm install -D @vitest/ui # Install vitest ui
npm install -D supertest # Install supertest to test http requests
npm install -D @types/supertest # Install types supertest
Create vite.config.ts
file with all vitest config
import tsconfigPaths from 'vite-tsconfig-paths'
import { defineConfig } from 'vitest/config'
export default defineConfig({
plugins: [tsconfigPaths()],
})
// now vitest can understand tsconfig paths
// Create scripts in package.json
"scripts": {
"test:create-prisma-environment": "npm link ./prisma/vitest-environment-prisma", // Create vitest-environment-prisma in node_modules
"test:install-prisma-environment": "npm link vitest-environment-prisma", // Install vitest-environment-prisma in node_modules
"test": "vitest run --dir src/use-cases", // Run all tests without watch
"test:watch": "vitest --dir src/use-cases", // Run all tests with watch
"pretest:e2e": "run-s test:create-prisma-environment test:install-prisma-environment", // Run before test:e2e, run-s is to run scripts in sequence (npm install -D npm-run-all)
"test:e2e": "vitest run --dir src/http", // Run all tests without watch in specific folder
"test:e2e:watch": "vitest --dir src/http", // Run all tests with watch in specific folder
"test:coverage": "vitest run --coverage", // Run all tests with coverage
"test:ui": "vitest --ui", // Run all tests with ui
},
Create vitest-environment-prisma
to test environment with prisma
cd prisma/vitest-environment-prisma # Enter in vitest-environment-prisma folder
npm init -y # Create package.json
npm link # Link vitest-environment-prisma to node_modules
cd ../../ # Return to root folder
npm link vitest-environment-prisma # Link vitest-environment-prisma to node_modules
Edit package.json
file like this
{
"name": "vitest-environment-prisma",
"main": "prisma-test-environment.ts"
}
Create prisma-test-environment.ts
in vitest-environment-prisma folder
Edit vite.config.ts
file with all vitest config
// Any test inside src/http/controllers will run in environment with prisma/vitest-environment-prisma
test: {
environmentMatchGlobs: [['src/http/controllers/**', 'prisma']],
},
npm install -D npm-run-all # Install npm-run-all to run multiple scripts in parallel or sequential
npm install bcryptjs # Install bcryptjs to encrypt password
npm install -D @types/bcryptjs # Install typescript types for bcryptjs
npm install dayjs # Install dayjs to manipulate date
- Deve ser possível se cadastrar na aplicação;
- Deve ser possível se autenticar na aplicação;
- Deve ser possível obter o perfil do usuário logado;
- Deve ser possível obter o número de check-ins do usuário logado;
- Deve ser possível o usuário obter seu histórico de check-ins;
- Deve ser possível o usuário buscar academias próximas a ele (até 10km);
- Deve ser possível o usuário buscar academias por nome;
- Deve ser possível o usuário fazer check-in em uma academia;
- Deve ser possível validar o check-in do usuário em uma academia;
- Deve ser possível cadastrar uma academia;
- O usuário não pode se cadastrar com um e-mail já existente;
- O usuário não pode fazer dois check-ins no mesmo dia;
- O usuário não pode fazer check-in se não estiver perto (100m) da academia;
- O check-in só pode ser validado até 20 minutos após criação;
- O check-in só pode ser validado por usuários administradores;
- A academia só pode ser cadastrada por usuários administradores;
- A senha do usuário deve ser armazenada com hash;
- Todas as listas de dados devem ser paginadas com 20 itens por página;
- O usuário deve ser identificado pelo token JWT;
- Uso de PostgreSQL em ambiente Dev e MySql em ambiente Prod;
- Uso de PrismaJs para migrations, queries e diagrama de banco de dados;
- Uso de Fastify para rotas e middlewares;
- Uso de Zod para validação de dados de entrada;
- Uso de SupertestJs para testes de integração;
- Uso de Tsup para compilar o TypeScript em modo de produção;
- Uso de Tsx para compilar o TypeScript em modo de desenvolvimento;
- Uso de Eslint para padronização de código;
- Uso de Prettier para padronização de código;
- Uso de Docker para deploy da aplicação e padronização de ambiente de desenvolvimento;
- Uso de Insonmia para testes de requisições;
- Uso de Github para versionamento de código;
- Uso Swagger para documentação da API;
git clone https://github.com/livioalvarenga/Template-Api-Rest-Node-Docker-Prisma.git # Clone este repositório
cd Template-Api-Rest-Node-Docker-Prisma # Acesse a pasta do projeto no seu terminal/cmd
npm install # Instale as dependências
npm run start-docker # Subir o banco de dados em modo de desenvolvimento na porta 5432
npm run dev # Execute a aplicação em modo de desenvolvimento, a aplicação será aberta na porta:3333 - acesse http://localhost:3333
npm run stop-docker # Parar o banco de dados em modo de desenvolvimento
# Ou
npm run lets-code # Sobe o banco de dados em modo de desenvolvimento e executa a aplicação em modo de desenvolvimento
npm run build # Compilar o TypeScript em modo de produção
npm run start # Iniciar o servidor em modo de produção
npm run studio # Iniciar o Prisma Studio para visualizar o banco de dados
npm run migrate # Criar migrations do banco de dados
npm run seed # Popular o banco de dados com dados de desenvolvimento
npm run generate # Gerar diagrama do banco de dados
A aplicação possui testes unitários de integração e testes e2e e uma cobertura de testes de 100%. Para executar os testes, execute os comandos abaixo:
npm run test # Executar os testes unitários de integração
npm run test:watch # Executar os testes unitários de integração com watch
npm run test:e2e # Executar os testes e2e
npm run test:e2e:watch # Executar os testes e2e com watch
npm run test:coverage # Verificar a cobertura de testes
npm run test:ui # Executar os testes de integração com Vitest ui
Além disso, utilizamos o GitHub Actions para executar os testes unitários de integração e e2e e verificar a cobertura de testes a cada push na branch main.
- Acesse http://localhost:3333/docs
- Create User in POST /users
- Authenticate User in POST /sessions _ Copy the token
- Click on Authorize button
- Paste the token in Value input
O deploy foi realizado na plataforma Render.com. Para acessar a rota de documentação (docs) da API, clique no link abaixo:
As variáveis de ambiente configuradas incluem:
- DATABASE_URL
- SHADOW_DATABASE_URL
- JWT_SECRET
- NODE_ENV
O comando para construção (Build command) foi configurado da seguinte forma:
npm install && npx prisma migrate deploy && npx prisma generate && npm run build
O banco de dados utilizado foi o MySQL MariaDB. Foi necessário criar um banco de dados sombra (Shadow), pois o serviço utilizado para criar o banco de dados não permite a criação de um banco de dados para testes. O Prisma utiliza um banco de dados sombra para realizar seus processos de migrações (migrations) e testes.
Olá, eu sou Livio Alvarenga, Engenheiro de Produção | Dev Back-end e Front-end. Sou aficcionado por tecnologia, programação, processos e planejamento. Uni todas essas paixões em uma só profissão. Dúvidas, sugestões e críticas são super bem vindas. Seguem meus contatos.
Este projeto é MIT licensed.