Siga a sequência abaixo ao adicionar um novo módulo ao backend. O exemplo usa o domínio hipotético Produto.
Crie src/middleware/schemas/Produto.Schema.js:
import { z } from "zod";
export const criarProdutoSchema = z.object({
nome: z.string().min(2).max(100),
preco: z.number().positive(),
});
Crie src/models/Produto.model.js:
import { Model } from "objection";
export class Produto extends Model {
static get tableName() { return "produtos"; }
}
Crie também a migration correspondente em db/migrations/ (arquivos .cjs; o diretório é configurado no knexfile.js).
Crie src/services/produtoService.js com toda a lógica de negócio:
import { Produto } from "#models/Produto.model.js";
export async function listarProdutos() {
return Produto.query().orderBy("Nome");
}
export async function criarProduto(dados) {
return Produto.query().insert(dados);
}
Crie src/controllers/Produto.Controller.js. Controllers são finos — apenas extraem dados da requisição e delegam ao service:
import * as produtoService from "#services/produtoService.js";
import { AppError } from "#shared/errors/AppError.js";
export const ProdutoController = {
Listar: async function (req, res, next) {
try {
const produtos = await produtoService.listarProdutos();
res.json({ produtos });
} catch (err) {
next(err);
}
},
Criar: async function (req, res, next) {
try {
const produto = await produtoService.criarProduto(req.body);
res.status(201).json({ produto });
} catch (err) {
next(err);
}
},
};
Crie src/routes/Produto.Rotas.js:
import { Router } from "express";
import { ProdutoController } from "#controllers/Produto.Controller.js";
import { requireUser } from "#middleware/RequireUser.js";
import { requireAdmin } from "#middleware/RequireAdmin.js";
import { validate } from "#middleware/Validate.js";
import { criarProdutoSchema } from "#middleware/schemas/Produto.Schema.js";
export const produtosRouter = Router();
produtosRouter.get("/", requireUser, ProdutoController.Listar);
produtosRouter.post("/", requireUser, requireAdmin, validate({ body: criarProdutoSchema }), ProdutoController.Criar);
Adicione o novo router em src/routes/index.js:
import { produtosRouter } from "./Produto.Rotas.js";
// dentro de IniciarRoteamento(app):
app.use("/api/produtos", produtosRouter);
Nomenclatura:
NomeDoModulo.Rotas.js (PascalCase)NomeDoModulo.Controller.js (PascalCase)nomeDoModuloService.js (camelCase)NomeDoModulo.model.js (PascalCase)NomeDoModulo.Schema.js (PascalCase)Imports: o código atual usa caminhos relativos em todo o src/ — siga esse padrão para manter consistência:
import { db } from "../config/db.config.js";
O
package.jsondefine o alias#*→./src/*, que é válido e funciona, mas ainda não é usado em nenhum arquivo dosrc/. Por ora, prefira imports relativos para alinhar ao restante do código. (Os exemplos acima usam#apenas para ilustrar; o código real usa../.)
Auth nas rotas:
requireUserrequireUser, requireAdminTratamento de erros:
try/catch e passe o erro para next(err)AppError para erros esperados (ex: não encontrado, sem permissão)ErrorHandler global formata a resposta automaticamenteDocumentação: