Skip to main content
Horse is incredibly versatile and supports multiple deployment scenarios. This page shows real examples from the samples directory, demonstrating how to build everything from simple console applications to Windows services and web server modules.

Console Applications

Basic REST API (Delphi)

The simplest way to get started with Horse is a console application:
program Console;

{$APPTYPE CONSOLE}

uses
  Horse,
  System.SysUtils;

begin
  {$IFDEF MSWINDOWS}
  IsConsole := False;
  ReportMemoryLeaksOnShutdown := True;
  {$ENDIF}

  THorse.Get('/ping',
    procedure(Req: THorseRequest; Res: THorseResponse)
    begin
      Res.Send('pong');
    end);

  THorse.Listen(9000,
    procedure
    begin
      Writeln(Format('Server is running on %s:%d', [THorse.Host, THorse.Port]));
      Readln;
    end);
end.
This example demonstrates the minimal setup needed for a Horse server. The callback in Listen is executed after the server starts.

Basic REST API (Lazarus)

For Lazarus/Free Pascal, use procedure-based routing:
program Console;

{$MODE DELPHI}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Horse;

procedure GetPing(Req: THorseRequest; Res: THorseResponse);
begin
  Res.Send('Ping');
end;

begin
  THorse.Get('/ping', GetPing);
  THorse.Listen(9000);
end.

GUI Applications

VCL Application with Start/Stop

Horse can be embedded in VCL applications for management interfaces:
unit Main.Form;

interface

uses
  Winapi.Windows, System.Classes, Vcl.Controls, Vcl.Forms,
  Vcl.StdCtrls, Vcl.Buttons, System.SysUtils;

type
  TFrmVCL = class(TForm)
    btnStop: TBitBtn;
    btnStart: TBitBtn;
    edtPort: TEdit;
    procedure btnStopClick(Sender: TObject);
    procedure btnStartClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    procedure Status;
    procedure Start;
    procedure Stop;
  end;

implementation

uses Horse;

procedure TFrmVCL.FormCreate(Sender: TObject);
begin
  THorse.Get('ping',
    procedure(Req: THorseRequest; Res: THorseResponse)
    begin
      Res.Send('pong');
    end);
end;

procedure TFrmVCL.Start;
begin
  // Need to set "HORSE_VCL" compilation directive
  THorse.Listen(StrToInt(edtPort.Text));
end;

procedure TFrmVCL.Stop;
begin
  THorse.StopListen;
end;

procedure TFrmVCL.Status;
begin
  btnStop.Enabled := THorse.IsRunning;
  btnStart.Enabled := not THorse.IsRunning;
  edtPort.Enabled := not THorse.IsRunning;
end;

procedure TFrmVCL.btnStartClick(Sender: TObject);
begin
  Start;
  Status;
end;

procedure TFrmVCL.btnStopClick(Sender: TObject);
begin
  Stop;
  Status;
end;

procedure TFrmVCL.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if THorse.IsRunning then
    Stop;
end;

end.
Important: Set the HORSE_VCL compilation directive in your project options for VCL applications.

Lazarus LCL Application

Similar functionality is available for Lazarus applications:
unit Views.Main;

{$MODE DELPHI}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, StdCtrls, Buttons, Horse;

type
  TFrmMain = class(TForm)
    btnStart: TBitBtn;
    btnStop: TBitBtn;
    edtPort: TEdit;
    procedure btnStartClick(Sender: TObject);
    procedure btnStopClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    procedure Status;
    procedure Start;
    procedure Stop;
  end;

implementation

procedure DoPing(Req: THorseRequest; Res: THorseResponse);
begin
  Res.Send('pong');
end;

procedure TFrmMain.FormCreate(Sender: TObject);
begin
  THorse.Get('/ping', DoPing);
end;

procedure TFrmMain.Status;
begin
  btnStop.Enabled := THorse.IsRunning;
  btnStart.Enabled := not THorse.IsRunning;
  edtPort.Enabled := not THorse.IsRunning;
end;

procedure TFrmMain.Start;
begin
  // Need to set "HORSE_LCL" compilation directive
  THorse.Listen(StrToInt(edtPort.Text));
end;

procedure TFrmMain.Stop;
begin
  THorse.StopListen;
end;

end.
Important: Set the HORSE_LCL compilation directive in your project options for LCL applications.

SSL/TLS Support

Horse supports SSL/TLS for secure HTTPS connections:
uses Horse, IdSSLOpenSSL;

procedure TfrmMain.Start;
begin
  // Configure SSL/TLS
  THorse.IOHandleSSL
    .KeyFile(leKey.Text)
    .CertFile(leCrt.Text)
    .OnGetPassword(Self.OnGetPassword)
    .SSLVersions([sslvTLSv1_2])
    .Active(True);

  THorse.Listen(edtPort.Value,
    procedure
    begin
      StatusBar1.Panels.Items[0].Text := 
        Format('Secure Server is running on https://%s:%d', 
               [THorse.Host, THorse.Port]);
    end);
end;

procedure TfrmMain.OnGetPassword(var Password: string);
begin
  Password := lePassword.Text;
end;
1

Generate SSL certificates

Use OpenSSL to generate self-signed certificates for testing:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout cert.key -out cert.crt
2

Add SSL libraries

Include libeay32.dll and ssleay32.dll (or OpenSSL 1.1+ equivalents) in your executable folder.
3

Configure Horse

Use IOHandleSSL to configure the key file, certificate file, and SSL versions.
Production Use: Self-signed certificates are not recommended for production. Use certificates from trusted authorities like Let’s Encrypt.

Web Server Modules

Apache Module

Deploy Horse as an Apache module:
library Apache;

uses Horse, Web.HTTPD24Impl;

var
  ApacheModuleData: TApacheModuleData;

exports
  ApacheModuleData name 'apache_horse_module';

begin
  // Need to set "HORSE_APACHE" compilation directive

  THorse.DefaultModule := @ApacheModuleData;
  THorse.HandlerName := 'apache_horse_module-handle';

  THorse.Get('/ping',
    procedure(Req: THorseRequest; Res: THorseResponse)
    begin
      Res.Send('pong');
    end);

  THorse.Listen;
end.
Apache Configuration (httpd.conf):
LoadModule apache_horse_module modules/Apache.dll

<Location /apache_horse>
  SetHandler apache_horse_module-handle
</Location>
Access your API at: http://localhost/apache_horse/ping
The dynamic library extension is .dll on Windows and .so on Linux.

ISAPI Module

Deploy Horse as an IIS ISAPI extension:
library ISAPI;

uses Horse;

begin
  // Need to set "HORSE_ISAPI" compilation directive

  THorse.Get('/ping',
    procedure(Req: THorseRequest; Res: THorseResponse)
    begin
      Res.Send('pong');
    end);

  THorse.Listen;
end.
1

Compile as library

Set project type to “Library” and add the HORSE_ISAPI compilation directive.
2

Deploy to IIS

Copy the compiled .dll to your IIS application directory.
3

Configure IIS

Add an ISAPI extension handler in IIS Manager pointing to your .dll file.

CGI Application

Deploy as a CGI executable:
program CGI;

{$APPTYPE CONSOLE}

uses Horse;

begin
  // Need to set "HORSE_CGI" compilation directive

  THorse.Get('/ping',
    procedure(Req: THorseRequest; Res: THorseResponse)
    begin
      Res.Send('pong');
    end);

  THorse.Listen;
end.
CGI is the slowest deployment method as a new process is spawned for each request. Consider FastCGI for better performance.

Service Applications

Linux Daemon

Run Horse as a Linux daemon:
program Daemon;

{$APPTYPE CONSOLE}

uses Horse, System.SysUtils;

begin
  // Need to set "HORSE_DAEMON" compilation directive

  THorse.Get('/ping',
    procedure(Req: THorseRequest; Res: THorseResponse)
    begin
      Res.Send('pong');
    end);

  THorse.Listen;
end.
Create a systemd service file:
[Unit]
Description=Horse API Service
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/horse-api
ExecStart=/opt/horse-api/daemon
Restart=always

[Install]
WantedBy=multi-user.target

Windows Service

Horse supports deployment as a Windows service with the HORSE_WINSVC directive. The full implementation is available in the samples/delphi/winsvc directory.
Windows service implementation requires additional service management code. Refer to the sample in samples/delphi/winsvc/ for a complete example.

Complete REST API Example

Here’s a more comprehensive REST API with multiple endpoints:
program RestAPI;

{$APPTYPE CONSOLE}

uses
  Horse,
  System.JSON,
  System.SysUtils;

type
  TUser = record
    Id: Integer;
    Name: string;
    Email: string;
  end;

var
  Users: array[1..3] of TUser = (
    (Id: 1; Name: 'John Doe'; Email: '[email protected]'),
    (Id: 2; Name: 'Jane Smith'; Email: '[email protected]'),
    (Id: 3; Name: 'Bob Wilson'; Email: '[email protected]')
  );

procedure GetUsers(Req: THorseRequest; Res: THorseResponse);
var
  JSONArray: TJSONArray;
  JSONUser: TJSONObject;
  User: TUser;
begin
  JSONArray := TJSONArray.Create;
  try
    for User in Users do
    begin
      JSONUser := TJSONObject.Create;
      JSONUser.AddPair('id', TJSONNumber.Create(User.Id));
      JSONUser.AddPair('name', User.Name);
      JSONUser.AddPair('email', User.Email);
      JSONArray.AddElement(JSONUser);
    end;
    Res.Send<TJSONArray>(JSONArray);
  finally
    JSONArray.Free;
  end;
end;

procedure GetUser(Req: THorseRequest; Res: THorseResponse);
var
  UserId: Integer;
  JSONUser: TJSONObject;
  User: TUser;
begin
  UserId := Req.Params['id'].ToInteger;
  
  for User in Users do
  begin
    if User.Id = UserId then
    begin
      JSONUser := TJSONObject.Create;
      try
        JSONUser.AddPair('id', TJSONNumber.Create(User.Id));
        JSONUser.AddPair('name', User.Name);
        JSONUser.AddPair('email', User.Email);
        Res.Send<TJSONObject>(JSONUser);
      finally
        JSONUser.Free;
      end;
      Exit;
    end;
  end;
  
  Res.Status(404).Send('User not found');
end;

begin
  // Routes
  THorse.Get('/users', GetUsers);
  THorse.Get('/users/:id', GetUser);
  
  // Start server
  THorse.Listen(9000,
    procedure
    begin
      Writeln('REST API running on http://localhost:9000');
      Writeln('Try: http://localhost:9000/users');
      Writeln('     http://localhost:9000/users/1');
      Readln;
    end);
end.

Sample Projects

Horse includes numerous sample projects demonstrating different use cases:

Console Applications

Basic standalone server applications
  • samples/delphi/console/
  • samples/lazarus/console/

GUI Applications

VCL and LCL applications with UI
  • samples/delphi/vcl/
  • samples/lazarus/lcl/

Web Server Modules

Apache, ISAPI, and CGI modules
  • samples/delphi/apache/
  • samples/delphi/isapi/
  • samples/delphi/cgi/

Services

Daemon and Windows Service examples
  • samples/delphi/daemon/
  • samples/delphi/winsvc/
All sample projects are available in the Horse GitHub repository.

Next Steps

Ecosystem

Explore middlewares and community tools

Deployment

Learn about production deployment strategies

Build docs developers (and LLMs) love