Recap do material — REST, validação, transações, erros de domínio.
CRUD HTTP completo: validação com zod, regras de negócio no service, transação no repository e middleware de erros.
Pausa para refeição e respiro antes do trabalho da tarde.
Implementar POST/PUT/DELETE da entidade do projeto com validação e tratamento padronizado de erros.
| Verbo | Rota | CRUD | Sucesso | Erros típicos |
|---|---|---|---|---|
| GET | /users | Read (lista) | 200 OK | 500 |
| GET | /users/:id | Read (item) | 200 OK | 404 Not Found |
| POST | /users | Create | 201 Created + Location | 400 · 409 · 422 |
| PUT | /users/:id | Replace (idempotente) | 200 OK | 404 · 422 |
| PATCH | /users/:id | Update parcial | 200 OK | 404 · 422 |
| DELETE | /users/:id | Delete (idempotente) | 204 No Content | 404 (ou 204 se idempotente puro) |
src/routes/index.ts agrega; cada recurso tem seu próprio Router():
routes/userRoutes.tsroutes/orderRoutes.tsroutes/productRoutes.tsVantagem: isolamento, testabilidade e onboarding rápido em times grandes.
req.body · valide antes de qualquer regraz.infer<typeof schema> dá o tipo TS de graça — uma fonte da verdade.
helpers/expect(parsePositiveInt("42")).toBe(42);
expect(parsePositiveInt("-1")).toBeNull();
AppError — base com status + messageNotFoundError → 404ConflictError → 409 (UNIQUE violado)ValidationError → 400err.stack nem detalhes do bancoasyncHandler — adeus try/catch repetidonext(err)router.post('/users', async (req, res, next) => {
try { ... } catch (e) { next(e); }
});
O try/catch aparece em todo handler.
router.post('/users', asyncHandler(async (req, res) => {
const u = await userService.create(req.body);
res.status(201).location(`/users/${u.id}`).json(u);
}));
Erros vão direto pro middleware central.
POST /ordersPOST /ordersEstoque ok → transação commit → 201 + Location header → cliente sabe onde buscar.
Estoque insuficiente → service lança ValidationError → middleware retorna 422 → nada foi gravado.
PUT /users/42 com mesmo body 5 vezes deixa o sistema no mesmo estado final que executar 1 vez.
Cliente pode tentar de novo após timeout sem medo.
POST /orders 5 vezes cria 5 pedidos. Cliente que dá retry sem cuidado duplica dados.
Avançado: header Idempotency-Key resolve.
DELETE /users/42 5 vezes deixa o user deletado uma vez. Após a 1ª, retornar 204 ou 404 é uma escolha de projeto.
{ data: ..., meta: {...} } — bom para paginação{ id, name, ... } — mais limpo, REST clássico{ error: "mensagem curta" }Você já tem endpoints implementados e regras de negócio mapeadas. Agora prove que o sistema atende ao negócio testando um fluxo inteiro como caixa-preta: a requisição entra no Controller, atravessa Service e Repository, e o efeito no banco é verificado.
Integrações externas (e-mail, storage, APIs de terceiros) são substituídas por mocks — o banco de dados não é mockado.
jest.mock()npm test com todos os casos passandobeforeEach)jest.mock()npm test apontando que todos passaramEsta aula: Visão Computational — endpoints HTTP completos com validação no controller e transações no repository.
Permitir criação, atualização e remoção do recurso central via HTTP, com validação de entrada e respostas consistentes.
| CONF Confiabilidade | ✅ Transações + erros tipados |
| SEG Segurança | ✅ Validação no controller |
| MANT Manutenibilidade | ✅ Camadas isoladas |
| USAB Usabilidade API | → Erros padronizados |
| DES Desempenho | → Pool reusado |
pg e middleware de erro. Na aula 7 a view EJS começa a renderizar essas respostas no servidor.
feat(api): crud completo recurso X.