CRUD API Walkthrough with Horse | Tour pelo exemplo CRUD com Horse

rust dev.to

Bilingual post · Post bilíngue

Jump to: English · Português


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
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

Run it

cd examples/crud
crab-pascal check crud.dpr
crab-pascal run crud.dpr
Enter fullscreen mode Exit fullscreen mode

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}'
Enter fullscreen mode Exit fullscreen mode

What this example stress-tests

  • Recursive unit loading (ProdutoService, Horse shim, JSON)
  • System.SysUtils string/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
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

Como rodar

cd examples/crud
crab-pascal check crud.dpr
crab-pascal run crud.dpr
Enter fullscreen mode Exit fullscreen mode

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}'
Enter fullscreen mode Exit fullscreen mode

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

Source: dev.to

arrow_back Back to Tutorials