API REST de exemplo construída com Express e TypeScript, organizada em camadas e pensada para fins didáticos: demonstrar, na prática, os princípios SOLID em uma aplicação simples de livros.
- Objetivo Didático
- Visão Geral
- Arquitetura e Fluxo
- Princípios SOLID na Prática
- Endpoints
- Como Rodar
- Estrutura de Pastas
- Roteiro de Palestra (Sugestão)
- Exercícios Propostos
- Perguntas Frequentes (FAQ)
- Mostrar como aplicar SOLID de forma pragmática em uma API Express.
- Destacar separação de responsabilidades, uso de contratos (interfaces) e injeção de dependências.
- Facilitar demonstrações e live coding em aulas/palestras.
- CRUD de livros: listar, buscar por ID, filtrar por ano, criar, atualizar e remover.
- Dados em memória para simplificar o foco nos princípios e arquitetura.
- Camadas claras: Controller → Service → Repository → Database, com
middlewaresevalidatorsauxiliares.
-
Camadas:
Controller(src/controllers/book-controller.ts): orquestraRequest/Responsee delega ao serviço.Service(src/services/book-service.ts): regras de negócio e casos de uso.Repository(src/repositories/book-repository.ts): contrato genérico e implementação para acesso a dados.Database(src/database.ts): dados em memória e modeloBook.Validators(src/validators/validator.ts): contratos e validação específica por recurso.Middlewares(src/middlewares.ts): preocupações transversais (log e validação básica de request).Routes(src/routes.ts): define endpoints e realiza o wiring das dependências.
-
Fluxo da requisição:
Request→middlewares(logger/validação) →controller→service→repository→database→Response.
-
SRP (Responsabilidade Única)
src/services/book-service.ts: cada método faz uma única coisa (listar, buscar, filtrar por ano, criar, atualizar, excluir).src/validators/validator.ts:BookValidatoreAuthorValidatorvalidam apenas seus respectivos modelos.src/middlewares.ts:loggerMiddlewareapenas loga;validateBookMiddlewareapenas valida formato.src/controllers/book-controller.ts: handlers focados em orquestrar request/response.
-
OCP (Aberto/Fechado)
IRepository<T>emsrc/repositories/book-repository.ts: permite novas implementações sem modificar a interface.- Validadores em
src/validators/validator.ts: adicionar novos validadores sem alterar os existentes. BookServiceaberto a novas fontes de dados viaIRepositorysem alterar a lógica do serviço.
-
LSP (Substituição de Liskov)
- Qualquer implementação de
IRepository<Book>pode substituirBookRepositorymantendo o contrato esperado;BookServicecontinua funcionando. AuthorValidatorimplementaIValidatore substitui sem quebrar comportamento.
- Qualquer implementação de
-
ISP (Segregação de Interfaces)
src/controllers/book-controller.ts: interfaces específicas (IGetBooks,ICreateBook,IUpdateBook,IDeleteBook) evitam depender de métodos não usados.IValidatordefine apenas o contrato mínimo de validação.
-
DIP (Inversão de Dependência)
BookServicedepende da abstraçãoIRepository<Book>, não da implementação concreta.src/routes.ts: composição das dependências na borda (instancia repositório → serviço → controller). Em projetos maiores, considerar mover o wiring paraapp.ts(composition root) ou usar um container de DI.
Base: http://localhost:3000
-
GET
/- Status do servidor.
- Retorna:
{"message":"servidor online!"}
-
GET
/books- Lista todos os livros.
- Query opcional:
ano(filtra por ano), ex.:/books?ano=1980.
-
GET
/books/:id- Busca um livro por ID.
- 200: objeto do livro; 404:
{"message":"Livro não encontrado!"}.
-
POST
/books- Cria um livro.
- Middleware:
validateBookMiddlewarevalidanome(string) eano(number). - Exemplo de corpo:
{ "nome": "Hábitos Atômicos", "ano": 2024 } - 201: objeto criado; 400: mensagens de validação.
-
PATCH
/books/:id- Atualiza parcialmente um livro.
- Exemplo:
{ "nome": "Novo Título" } - 200: objeto atualizado; 404: não encontrado.
-
DELETE
/books/:id- Remove um livro.
- 204: sem conteúdo; 404: não encontrado.
Arquivo src/database.ts:
export interface Book {
id?: number;
nome?: string;
ano?: number;
}Pré-requisitos:
- Node.js (LTS recomendado)
- npm
Instalação:
npm installDesenvolvimento:
npm run devHot reload (dev com reinício automático):
npm run watchBuild (TypeScript → JavaScript):
npm run buildStart (produção; depende do build):
npm startObservações:
- Variável
PORTpode ser usada para alterar a porta (padrão3000). - Em dev, o entrypoint é
src/app.ts; em prod,dist/index.js(viaprestart).
├── .gitignore
├── README.MD
├── package-lock.json
├── package.json
├── src/
│ ├── app.ts # Inicializa Express e monta o router
│ ├── controllers/
│ │ └── book-controller.ts # Handlers HTTP orquestram o serviço
│ ├── database.ts # Modelo e dados em memória
│ ├── middlewares.ts # Logger e validação básica
│ ├── repositories/
│ │ └── book-repository.ts # Contrato genérico + implementação Book
│ ├── routes.ts # Endpoints e wiring das dependências
│ ├── services/
│ │ └── book-service.ts # Regras de negócio
│ └── validators/
│ └── validator.ts # Contratos e validadores
└── tsconfig.json
Esta aplicação oferece um terreno simples e eficaz para ensinar e praticar SOLID em APIs Express. A separação em camadas, o uso de interfaces e a injeção de dependências permitem evoluir e testar com mínimo acoplamento.