API RESTful no estilo GymPass — cadastro de academias, check-in geolocalizado e controle de acesso por papéis (ADMIN / MEMBER), construída com rigor nos princípios SOLID.
- Sobre o Projeto
- Regras de Negócio
- Arquitetura
- Endpoints da API
- Modelos de Dados
- Stack Tecnológica
- Como Executar
- Testes
- CI/CD
- Variáveis de Ambiente
- Autor
A GymPass Style API é uma API RESTful que replica o core de um serviço de assinatura de academias. Ela permite que usuários se cadastrem, autentiquem, localizem academias próximas por geolocalização e realizem check-ins diários. Administradores podem cadastrar academias e validar check-ins presencialmente.
O projeto foi desenvolvido como laboratório de boas práticas de engenharia de software em Node.js, com foco em:
- Princípios SOLID aplicados em cada camada da aplicação
- Repository Pattern com inversão de dependência entre Use Cases e persistência
- Factory Pattern para composição de casos de uso sem acoplamento
- Testes em dupla camada: unitários (Use Cases isolados) e E2E (HTTP real + banco de dados real)
- Autenticação stateless com JWT de curta duração + Refresh Token via cookie
HttpOnly
- Cadastro único por e-mail (duplicatas retornam erro)
- Senha armazenada como hash
bcrypt - Papéis:
MEMBER(padrão) eADMIN - Acesso ao próprio perfil autenticado
- Somente
ADMINpode cadastrar academias - Busca por nome (texto parcial) com paginação
- Busca por proximidade geográfica (até 10 km do usuário)
- Apenas 1 check-in por dia por academia
- A academia deve estar dentro de 100 metros da coordenada informada
- Validação do check-in (presencial) apenas por
ADMIN - Validação permitida somente até 20 minutos após a criação do check-in
- Histórico paginado de check-ins do usuário autenticado
- Métrica de total de check-ins realizados
src/
├── app.ts # Bootstrap do Fastify (plugins, rotas, error handler)
├── server.ts # Entry point (listen)
├── config/
│ └── env.ts # Variáveis de ambiente validadas com Zod
├── db/
│ └── prisma.ts # Singleton do PrismaClient
├── http/
│ ├── controllers/
│ │ ├── users/ # register · authenticate · profile · refresh
│ │ ├── gyms/ # create · search · nearby
│ │ └── check-ins/ # create · validate · history · metrics
│ └── middlewares/
│ ├── verify-jwt.ts # Guarda JWT em todas as rotas protegidas
│ └── verify-user-role.ts # RBAC — restringe rotas por papel
├── use-cases/
│ ├── *.ts # Casos de uso (lógica de negócio pura)
│ ├── errors/ # Erros de domínio tipados
│ └── factories/ # Fábricas de injeção de dependência
└── repositories/
├── interfaces/ # Contratos (inversão de dependência)
└── prisma/ # Implementações Prisma dos repositórios
| Princípio | Aplicação |
|---|---|
| S — Single Responsibility | Cada Use Case resolve exatamente um caso de uso de negócio |
| O — Open/Closed | Novos repositórios são adicionados implementando a interface, sem alterar Use Cases |
| L — Liskov Substitution | In-memory repositories nos testes unitários substituem os Prisma sem quebrar contratos |
| I — Interface Segregation | Repositórios têm interfaces separadas (IUsersRepository, IGymsRepository, ICheckInsRepository) |
| D — Dependency Inversion | Use Cases dependem de abstrações (interfaces), não de PrismaClient diretamente |
| Método | Rota | Auth | Descrição |
|---|---|---|---|
POST |
/users |
— | Cadastrar novo usuário |
POST |
/sessions |
— | Autenticar e obter JWT |
PATCH |
/token/refresh |
Cookie | Renovar access token |
GET |
/me |
JWT | Perfil do usuário autenticado |
| Método | Rota | Auth | Role | Descrição |
|---|---|---|---|---|
POST |
/gyms |
JWT | ADMIN | Cadastrar academia |
GET |
/gyms/search |
JWT | — | Buscar academias por nome |
GET |
/gyms/nearby |
JWT | — | Academias em até 10 km |
| Método | Rota | Auth | Role | Descrição |
|---|---|---|---|---|
POST |
/gyms/:gymId/check-ins |
JWT | — | Realizar check-in |
PATCH |
/check-ins/:checkInId/validate |
JWT | ADMIN | Validar check-in |
GET |
/check-ins/history |
JWT | — | Histórico paginado |
GET |
/check-ins/metrics |
JWT | — | Total de check-ins |
Token de acesso expira em 10 minutos. O refresh token é armazenado em cookie
HttpOnlye renova o acesso transparentemente.
model User {
id String @id @default(uuid())
name String
email String @unique
password_hash String
role Role @default(MEMBER) // ADMIN | MEMBER
created_at DateTime @default(now())
checkIns CheckIn[]
}
model Gym {
id String @id @default(uuid())
title String
description String?
phone String?
latitude Decimal
longitude Decimal
checkIns CheckIn[]
}
model CheckIn {
id String @id @default(uuid())
created_at DateTime @default(now())
validated_at DateTime? // nulo até validação pelo ADMIN
user_id String
gym_id String
}- Node.js 22 — runtime LTS
- Fastify 5 — framework HTTP de alta performance com suporte nativo a TypeScript
- TypeScript 6 — tipagem estrita com
noUncheckedIndexedAccesseexactOptionalPropertyTypes
- PostgreSQL 16 — banco relacional robusto com suporte a tipos geográficos via
Decimal - Prisma 7 — ORM type-safe com migrations automatizadas e client gerado em
src/generated/prisma @prisma/adapter-pg— adaptador de driver para pg nativo
- Zod 4 — validação de schemas em runtime com inferência de tipos
fastify-type-provider-zod— integração de Zod como validator/serializer do Fastify@fastify/jwt— autenticação JWT com suporte a cookie@fastify/cookie— gerenciamento de cookies para refresh token- bcryptjs — hash seguro de senhas
- dayjs — manipulação de datas para lógica de validação de check-in
- dotenv — gerenciamento de variáveis de ambiente
- pino-pretty — logs coloridos em desenvolvimento
- Vitest 4 — framework de testes com projetos separados (
unitee2e) - Supertest — testes de integração HTTP sem levantar servidor real
vitest-environment-prisma— ambiente customizado que cria um schema isolado por suíte E2E
- pnpm 10 — gerenciador de pacotes eficiente
- tsup — bundler baseado em esbuild para build de produção ESM
- tsx — executor TypeScript para desenvolvimento com hot reload
- ESLint 10 + Prettier — análise estática e formatação consistente
- Docker Compose — PostgreSQL + pgAdmin containerizados
- Node.js 22+
- pnpm 10+
- Docker e Docker Compose
git clone https://github.com/Cardosofiles/apirest-solid-course.git
cd apirest-solid-coursepnpm installcp .env.example .env
# Edite o .env conforme necessáriodocker compose up -dpnpm db:migratepnpm devO servidor estará disponível em http://localhost:3333.
pnpm db:studio # Abrir Prisma Studio (GUI do banco)
pnpm build # Build de produção (ESM via tsup)
pnpm start # Iniciar build de produçãoA suíte de testes é dividida em dois projetos independentes:
Repositórios in-memory substituem Prisma, garantindo velocidade e isolamento total.
pnpm test # Execução única
pnpm test:watch # Modo watch
pnpm test:coverage # Com relatório de cobertura
pnpm test:ui # Interface gráfica do VitestCada suíte recebe um schema PostgreSQL isolado (criado e destruído automaticamente pelo vitest-environment-prisma). Não há mocks — a requisição percorre toda a stack.
pnpm test:e2e # Execução única
pnpm test:watch:e2e # Modo watch| Camada | Abordagem |
|---|---|
| Use Cases | Unitário com in-memory repositories |
| Controllers HTTP | E2E com Supertest + Prisma + PostgreSQL real |
| Middlewares | Cobertos pelos testes E2E |
Dois workflows no GitHub Actions:
| Workflow | Gatilho | O que executa |
|---|---|---|
run-unit-tests.yml |
Push em qualquer branch | pnpm test (testes unitários) |
run-e2e-tests.yml |
Pull Request | pnpm test:e2e com PostgreSQL via bitnami/postgresql service |
Crie um arquivo .env na raiz com base no .env.example:
# Banco de dados
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/gympass_style_db?schema=public"
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=gympass_style_db
POSTGRES_PORT=5432
# pgAdmin
PGADMIN_EMAIL=admin@admin.com
PGADMIN_PASSWORD=admin
PGADMIN_PORT=5050
# Aplicação
NODE_ENV=development
PORT=3333
JWT_SECRET=sua-chave-secreta-aqui
JWT_SECRETdeve ser uma string longa e aleatória em produção. O access token expira em 10 minutos; o refresh token não possui prazo definido pelo servidor, mas deve ser rotacionado a cada uso.
Desenvolvido com foco em qualidade, arquitetura e boas práticas de engenharia de software.
