@ministerjs/server
v3.7.0
Published
Pacote de integração backend para o MinisterJS. Fornece endpoints REST auto-gerados via controllers NestJS, um repositório baseado em Prisma com hooks de ciclo de vida, mapeamento de campos, soft delete e um sistema de schema de entidades com validação.
Readme
@ministerjs/server
Pacote de integração backend para o MinisterJS. Fornece endpoints REST auto-gerados via controllers NestJS, um repositório baseado em Prisma com hooks de ciclo de vida, mapeamento de campos, soft delete e um sistema de schema de entidades com validação.
Instalação
pnpm add @ministerjs/serverDependências peer:
pnpm add @ministerjs/resource @ministerjs/utils @nestjs/common @prisma/client class-validator nestjs-form-dataInício Rápido
1. Defina um Schema de Entidade
import { field, buildEntitySchema } from "@ministerjs/server/entity";
import { IsEmail } from "class-validator";
const UserSchema = buildEntitySchema("user", {
primaryKey: "id",
fields: {
id: field("string").build(),
name: field("string").searchable().requireInCreate().build(),
email: field("string")
.searchable()
.requireInCreate()
.validate(IsEmail())
.build(),
role: field("string").optional().build(),
},
parents: [],
children: { orders: "user_id" },
});2. Crie um Repositório
import { PrismaRepository } from "@ministerjs/server/prisma";
const userRepository = new PrismaRepository({
prisma,
schema: UserSchema,
softDelete: true, // opcional
});3. Crie um Controller
import { NestJsTableController } from "@ministerjs/server/nestjs";
import { Controller } from "@nestjs/common";
@Controller("users")
class UsersController extends NestJsTableController {
constructor() {
super(userRepository, {
schema: UserSchema,
hooks: {
beforeCreate: ({ body }) => {
body.role = body.role ?? "user";
},
afterCreate: ({ data }) => {
console.log("Usuário criado:", data.id);
},
},
});
}
}Isso gera automaticamente os seguintes endpoints:
| Método | Rota | Descrição |
|--------|--------------|-----------------------------------------------|
| GET | /users | Listar com paginação, busca, filtros e ordenação |
| GET | /users/:id | Buscar por ID com parents e children |
| POST | /users | Criar com validação |
| PUT | /users/:id | Atualizar com validação |
| DELETE | /users/:id | Deletar (soft ou hard) |
Exports do Pacote
import { field, buildEntitySchema } from "@ministerjs/server/entity";
import { NestJsTableController, NestJsItemController, parseListQuery } from "@ministerjs/server/nestjs";
import { PrismaRepository } from "@ministerjs/server/prisma";| Entry Point | Conteúdo |
|-------------|----------|
| @ministerjs/server/entity | field(), buildEntitySchema(), tipos do schema |
| @ministerjs/server/nestjs | NestJsTableController, NestJsItemController, parseListQuery |
| @ministerjs/server/prisma | PrismaRepository, utilitários de field mapping, specifications |
Schema de Entidade
O builder field() define metadados a nível de campo:
field("string")
.searchable() // Incluir na busca textual
.requireInCreate() // Obrigatório no POST
.optionalInUpdate() // Opcional no PUT
.validate(IsEmail()) // Decorator do class-validator
.getter(e => e.name?.toUpperCase()) // Transformar na leitura
.setter(e => e.name?.toLowerCase()) // Transformar na escrita
.build()Validação suporta tanto decorators do class-validator quanto ObjectValidator customizados:
const emailUnico = {
validate: async (target, prop, { request }) => {
const existente = await userRepo.getByProperty("email", target[prop]);
if (existente) throw new Error("Email já está em uso");
},
};
field("string").validate(IsEmail(), emailUnico).build();PrismaRepository
Repositório completo com operações CRUD tipadas:
const repo = new PrismaRepository({
prisma, // Instância do PrismaClient
schema, // Schema de entidade via buildEntitySchema()
softDelete: false, // Habilitar soft delete (padrão: false)
fieldMapping: {}, // Mapeamento de nomes de campos (opcional)
logger: console, // Logger customizado (opcional)
defaultResultsPerPage: 25,
});Operações de Leitura
await repo.get(id);
await repo.getByProperty("email", "[email protected]");
await repo.getByProperties({ name: "John", role: "admin" });
await repo.list({ page: 1, resultsPerPage: 10, search: "john", sort, filters });
await repo.listWithCursor({ cursor: lastId, take: 20 }); // Paginação por cursor
await repo.count();Operações de Escrita
await repo.create({ name: "John", email: "[email protected]" });
await repo.createMany([{ name: "A" }, { name: "B" }]); // Criação em lote
await repo.update(id, { name: "Jane" });
await repo.updateProperty(id, "role", "admin");
await repo.updatePropertyMany("role", [{ id: "1", role: "admin" }, { id: "2", role: "user" }]);
await repo.delete(id);Relacionamentos
await repo.getParent(orderId, "user");
await repo.listParents(orderId);
await repo.getChildren(userId, "orders");
await repo.listChildren(userId);
await repo.countChildren(userId, "orders");Hooks de Ciclo de Vida
Ambos os controllers suportam hooks em cada ponto do ciclo de vida:
Hooks do NestJsTableController
CREATE: beforeValidateCreate -> [validação] -> beforeCreate -> [BD] -> afterCreate
SHOW: beforeShow -> [BD + relações] -> afterShow
LIST: beforeList -> [consulta BD] -> afterList
UPDATE: beforeValidateUpdate -> [validação] -> beforeUpdate -> [BD] -> afterUpdate
DELETE: beforeDelete -> [BD] -> afterDeleteRegistro de Hooks
// Via construtor
new NestJsTableController(repo, {
schema,
hooks: {
beforeCreate: ({ body, request }) => { /* ... */ },
afterDelete: ({ id, data }) => { /* ... */ },
},
});
// Via addHook (múltiplos handlers, chamados em ordem)
controller.addHook("beforeCreate", handler1, handler2);
// Via bindHook (um handler para múltiplos eventos)
controller.bindHook(auditLogger, "beforeCreate", "beforeUpdate", "beforeDelete");Guias
- Mapeamento de Campos - Mapear campos da API para caminhos internos do Prisma
- Padrão Specification - Filtros de consulta composíveis
- Soft Delete - Configuração e uso
- Troubleshooting - Erros comuns e soluções
- Exemplos Avançados - Hooks, validators, paginação por cursor
Desenvolvimento
pnpm --filter @ministerjs/server test # Executar testes
pnpm --filter @ministerjs/server build # Build (lint + types + bundle)
pnpm --filter @ministerjs/server build:types # Gerar declarações de tipos
pnpm --filter @ministerjs/server dev # Modo watch