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;
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
Add SSL libraries
Include libeay32.dll and ssleay32.dll (or OpenSSL 1.1+ equivalents) in your executable folder.
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.
Compile as library
Set project type to “Library” and add the HORSE_ISAPI compilation directive.
Deploy to IIS
Copy the compiled .dll to your IIS application directory.
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/
Next Steps
Ecosystem Explore middlewares and community tools
Deployment Learn about production deployment strategies