English {#english}
CRUD API Walkthrough with Horse
The best proof of a Pascal compiler is not another hello world — it is a small but real HTTP service. CrabPascal ships examples/crud/, a product CRUD API built with Horse, System.JSON, and generics collections. This walkthrough shows how the pieces fit and how to run it locally.
Project layout
examples/crud/
crud.dpr ← HTTP routes and server bootstrap
ProdutoService.pas ← business logic + in-memory store
The program file registers REST endpoints; the service unit encapsulates validation and JSON serialization.
Bootstrapping the server
program CrudAPI;
uses
System.SysUtils,
Horse,
System.JSON,
ProdutoService;
begin
WriteLn('CrabPascal CRUD API Server');
THorse.Get('/produtos',
procedure(Req: THorseRequest; Res: THorseResponse; Next: TNextProc)
begin
Res.Send<TJSONObject>(TProdutoService.ListarProdutos);
end);
THorse.Listen(9000);
end.
Horse mirrors Delphi's middleware style: anonymous procedures as handlers, fluent route registration.
Service layer with generics
ProdutoService.pas defines a record and a class with static methods:
type
TProduto = record
Id: Integer;
Nome: string;
Preco: Double;
Categoria: string;
Estoque: Integer;
Ativo: Boolean;
end;
TProdutoService = class
private
class var FProdutos: TList<TProduto>;
class var FNextId: Integer;
public
class function ListarProdutos: TJSONObject;
class function CriarProduto(const Nome, Categoria: string;
Preco: Double; Estoque: Integer): TJSONObject;
end;
TList<TProduto> exercises generics monomorphization. JSON responses use System.JSON types (TJSONObject, TJSONArray).
Sample routes
| Method | Path | Action |
|---|---|---|
| GET | /produtos |
List all products |
| GET | /produtos/:id |
Get by ID |
| POST | /produtos |
Create from JSON body |
| PUT | /produtos/:id |
Update |
| DELETE | /produtos/:id |
Soft delete |
POST handler sketch:
THorse.Post('/produtos',
procedure(Req: THorseRequest; Res: THorseResponse; Next: TNextProc)
var
json: TJSONObject;
begin
json := Req.Body<TJSONObject>;
Res.Send(TProdutoService.CriarProduto(
json.GetValue('nome').Value,
json.GetValue('categoria').Value,
StrToFloatDef(json.GetValue('preco').Value, 0),
StrToIntDef(json.GetValue('estoque').Value, 0)));
end);
Run it
cd examples/crud
crab-pascal check crud.dpr
crab-pascal run crud.dpr
Test with curl:
curl http://localhost:9000/produtos
curl -X POST http://localhost:9000/produtos \
-H "Content-Type: application/json" \
-d '{"nome":"Keyboard","categoria":"Perifericos","preco":199.90,"estoque":10}'
What this example stress-tests
- Recursive unit loading (
ProdutoService, Horse shim, JSON) -
System.SysUtilsstring/number helpers - Anonymous procedures capturing variables
- Class static fields and initialization
- HTTP + JSON stack used in real Delphi microservices
E2E scripts crud_list_e2e.pas and crud_full_e2e.pas extend coverage for automated runs.
Limitations
In-memory store resets each run. Authentication, database persistence, and HTTPS termination are out of scope — intentionally, to keep the example readable.
Next steps
Fork the example, swap TProduto for your domain model, and report compiler gaps with a minimal diff. Follow @crabpascal for sprint news as Horse parity improves.
Português {#portugus}
Tour pelo exemplo CRUD com Horse
A melhor prova de compilador Pascal não é outro hello world — é um serviço HTTP pequeno mas real. O CrabPascal inclui examples/crud/, API CRUD de produtos com Horse, System.JSON e collections genéricas. Este tour mostra como as peças se encaixam e como rodar localmente.
Layout do projeto
examples/crud/
crud.dpr ← rotas HTTP e bootstrap do servidor
ProdutoService.pas ← lógica de negócio + store em memória
O program registra endpoints REST; a unit de serviço encapsula validação e serialização JSON.
Subindo o servidor
program CrudAPI;
uses
System.SysUtils,
Horse,
System.JSON,
ProdutoService;
begin
WriteLn('CrabPascal CRUD API Server');
THorse.Get('/produtos',
procedure(Req: THorseRequest; Res: THorseResponse; Next: TNextProc)
begin
Res.Send<TJSONObject>(TProdutoService.ListarProdutos);
end);
THorse.Listen(9000);
end.
Horse espelha estilo middleware Delphi: procedures anônimas como handlers, registro fluente de rotas.
Camada de serviço com generics
ProdutoService.pas define record e classe com métodos estáticos:
type
TProduto = record
Id: Integer;
Nome: string;
Preco: Double;
Categoria: string;
Estoque: Integer;
Ativo: Boolean;
end;
TProdutoService = class
private
class var FProdutos: TList<TProduto>;
class var FNextId: Integer;
public
class function ListarProdutos: TJSONObject;
class function CriarProduto(const Nome, Categoria: string;
Preco: Double; Estoque: Integer): TJSONObject;
end;
TList<TProduto> exercita monomorphização de generics. Respostas JSON usam tipos System.JSON (TJSONObject, TJSONArray).
Rotas principais
| Método | Path | Ação |
|---|---|---|
| GET | /produtos |
Listar todos |
| GET | /produtos/:id |
Buscar por ID |
| POST | /produtos |
Criar via JSON body |
| PUT | /produtos/:id |
Atualizar |
| DELETE | /produtos/:id |
Exclusão lógica |
Esboço do handler POST:
THorse.Post('/produtos',
procedure(Req: THorseRequest; Res: THorseResponse; Next: TNextProc)
var
json: TJSONObject;
begin
json := Req.Body<TJSONObject>;
Res.Send(TProdutoService.CriarProduto(
json.GetValue('nome').Value,
json.GetValue('categoria').Value,
StrToFloatDef(json.GetValue('preco').Value, 0),
StrToIntDef(json.GetValue('estoque').Value, 0)));
end);
Como rodar
cd examples/crud
crab-pascal check crud.dpr
crab-pascal run crud.dpr
Teste com curl:
curl http://localhost:9000/produtos
curl -X POST http://localhost:9000/produtos \
-H "Content-Type: application/json" \
-d '{"nome":"Teclado","categoria":"Perifericos","preco":199.90,"estoque":10}'
O que o exemplo stressa
- Carregamento recursivo de units (
ProdutoService, shim Horse, JSON) - Helpers string/número de
System.SysUtils - Procedures anônimas capturando variáveis
- Fields estáticos de classe e initialization
- Stack HTTP + JSON de microserviços Delphi reais
Scripts E2E crud_list_e2e.pas e crud_full_e2e.pas estendem cobertura automatizada.
Limitações
Store em memória reseta a cada execução. Autenticação, persistência em banco e HTTPS ficam fora — de propósito, para manter o exemplo legível.
Próximos passos
Faça fork do exemplo, troque TProduto pelo seu domínio e reporte gaps do compilador com diff mínimo. Siga @crabpascal para novidades de sprint na paridade Horse.
Published on dev.to/@crabpascal · Código em CrabPascal