horse-crud
Middleware de Auto-CRUD de alta performance para o framework Horse. Gere automaticamente rotas CRUD completas (GET, POST, PUT, DELETE) com injeção de persistência genérica de forma thread-safe e multiplataforma (Delphi & Lazarus/FPC).
- Active · last change 7-31-2026
- ★ 6 on GitHub
README
horse-crud
Middleware para o framework Horse voltado à geração automática e dinâmica de rotas CRUD (Create, Read, Update, Delete) a partir de entidades decoradas, compatível com Delphi XE7+ e Lazarus/FPC (Windows/Linux).
O horse-crud adota o padrão Repository/Store Decoupled Auto-CRUD, separando completamente o ciclo de vida HTTP do mecanismo de persistência de banco de dados. A persistência real é delegada ao desenvolvedor através de uma fábrica de repositórios, garantindo que as conexões de banco sejam seguras e isoladas por requisição (Thread-Safety).
🏛️ Padrão Repository/Store Decoupled
Ao registrar o middleware CRUD automático para uma classe de negócio (ex: TCliente), o horse-crud gerencia o ciclo HTTP e delega as operações de persistência à interface genérica IHorseRepository<T>.
A fábrica de conexões (THorseCrudRepositoryFactory<T>) permite retornar instâncias novas dos repositórios a cada requisição (thread), prevenindo deadlocks e compartilhamento de conexões (essencial ao usar drivers como FireDAC ou SQLdb do FPC).
sequenceDiagram
Client->>Horse: GET /clientes
Horse->>THorseCrud: DoGet
THorseCrud->>Factory: Solicita Repositório
Factory-->>THorseCrud: Retorna IHorseRepository<T>
THorseCrud->>Repository: FindAll()
Repository-->>THorseCrud: TObjectList<T>
THorseCrud->>THorseCrud: Serializa e libera a lista
THorseCrud-->>Client: 200 OK (JSON Array)⚙️ Instalação
A instalação deve ser feita utilizando o gerenciador de pacotes boss:
boss4d package install horse-crud@1.0.0📖 Exemplos Práticos
1. Declaração do Model e Interface de Repositório
Defina seu model decorado com atributos e crie a classe repositório que implementa IHorseRepository<T>:
unit Model.Cliente;
interface
uses
{$IFNDEF FPC} Horse.CRUD {$ENDIF};
type
{$M+}
{$IFNDEF FPC}
[Entity('/clientes')]
{$ENDIF}
TCliente = class
private
FId: Integer;
FNome: string;
published
{$IFNDEF FPC} [Key] {$ENDIF}
property Id: Integer read FId write FId;
property Nome: string read FNome write FNome;
end;unit Repository.Cliente;
interface
uses
SysUtils, Generics.Collections, Horse.CRUD.Interfaces, Model.Cliente;
type
TClienteRepository = class(TInterfacedObject, IHorseRepository<TCliente>)
public
function FindAll: TObjectList<TCliente>;
function Find(const AId: string): TCliente;
procedure Insert(const AEntity: TCliente);
procedure Update(const AEntity: TCliente);
procedure Delete(const AId: string);
end;
function ClienteRepositoryFactory: IHorseRepository<TCliente>;
implementation
function ClienteRepositoryFactory: IHorseRepository<TCliente>;
begin
Result := TClienteRepository.Create;
end;
// Implementações do Repositório (FindAll, Find, Insert, Update, Delete)...2. Registro do Auto-CRUD no Servidor Horse
No arquivo principal do servidor, configure o middleware de JSON (como o Jhonson) e registre as entidades que deseja expor automaticamente:
uses
SysUtils,
Horse,
Horse.Jhonson,
Horse.CRUD,
Model.Cliente,
Repository.Cliente;
begin
// O Jhonson fará a serialização de objetos e arrays automaticamente
THorse.Use(Jhonson());
// Registro automático de rotas CRUD da entidade TCliente usando a fábrica portátil
THorseCrud<TCliente>.Register(ClienteRepositoryFactory);
THorse.Listen(9000);
end.O horse-crud irá mapear automaticamente os seguintes endpoints:
GET /clientes-> Retorna todos os registros (FindAll).GET /clientes/:id-> Retorna um registro por ID (Find).POST /clientes-> Insere uma entidade (Insert).PUT /clientes/:id-> Atualiza uma entidade (Update).DELETE /clientes/:id-> Exclui um registro por ID (Delete).
⚡ Segurança de Memória e Thread-Safety
- Thread-Safety: O repositório é instanciado na thread ativa que atende à requisição HTTP por meio da fábrica passada no
Register. Após a requisição terminar, o repositório é desalocado (por ser gerenciado como interfaceIHorseRepository<T>). - Memory Leaks: O controller assume a propriedade das listas e entidades retornadas pelo repositório e as libera imediatamente depois de serializar a resposta. O repositório deve retornar instâncias independentes.
🛠️ Portabilidade e Lazarus/FPC
O horse-crud foi projetado para portabilidade total. No Lazarus/FPC:
- Como o FPC não oferece suporte nativo a closures/métodos anônimos, a fábrica
THorseCrudRepositoryFactory<T>é mapeada como um ponteiro de função padrão (function). Você deve declarar uma função global tradicional (ex:ClienteRepositoryFactory) e passá-la como parâmetro. - Como o compilador Lazarus/FPC não suporta atributos de RTTI moderna (
[Entity],[Key]), você deve passar a rota e a propriedade de ID de forma explícita no momento do registro:
// No Lazarus/FPC o registro explícito das rotas e chaves é obrigatório
THorseCrud<TCliente>.Register(
ClienteRepositoryFactory,
'/clientes', // Caminho explícito
'Id' // Nome da chave primária explícito
);📄 Licença
Este projeto está licenciado sob a Apache License 2.0.

