Horse Request & Response
THorseRequest (Reading Request Data)
The THorseRequest object contains all details of the incoming HTTP request.
Safe Parameter Parsing & Validation (THorseCoreParamField)
Instead of accessing raw string dictionary values (e.g., Req.Params['id']) and converting them manually, always prefer using the .Field() method to obtain a THorseCoreParamField. This provides type-safe conversions and declarative parameter validation:
- Type Conversion: Convert parameters to the target type without manually calling
StrToInt or StrToBool:var
LId: Integer;
LActive: Boolean;
LDate: TDateTime;
begin
LId := Req.Params.Field('id').AsInteger;
LActive := Req.Query.Field('active').AsBoolean;
LDate := Req.Query.Field('since').AsISO8601DateTime;
end;
- Required Check: Automatically halt execution and return a 400 Bad Request with a custom error message if the parameter is missing:
var
LEmail: string;
begin
// Automatically raises EHorseException if 'email' query param is empty
LEmail := Req.Query.Field('email').Required.RequiredMessage('The "email" parameter is required.').AsString;
end;
- Supported Converters:
AsInteger, AsInt64, AsBoolean, AsFloat, AsCurrency, AsDateTime, AsISO8601DateTime, AsStream (for multipart uploads), and AsString.
Cookies Management
Horse provides a provider-agnostic, typed API to read cookies from requests and write them back in responses (RFC 6265 compliant).
Reading Cookies: Read incoming cookies safely using the .Field() helper:
var
LSessionToken: string;
begin
LSessionToken := Req.Cookie.Field('session_token').AsString;
end;
Writing Cookies (Set-Cookie): Write response cookies using Res.Cookie and configure properties fluently:
uses Horse.Core.Cookie;
procedure SetCookieHandler(Req: THorseRequest; Res: THorseResponse; Next: TProc);
begin
// Creates, registers, and configures the cookie fluently (XE7 compatible)
Res.Cookie('session_id', 'xyz789')
.Path('/')
.HttpOnly(True)
.Secure(True)
.SameSite(TSameSite.ssLax);
Res.Send('Cookie has been set');
end;
THorseResponse (Sending HTTP Responses)
The THorseResponse object is used to build and send the HTTP response back to the client.
- Send: Returns text or objects. It supports method chaining:
// Sending simple text with Status 200 (OK)
Res.Send('Success');
// Setting Status 201 (Created) and sending an object (MUST set status BEFORE calling Send)
Res.Status(THTTPStatus.Created).Send<TJSONObject>(LJson);
- Status: Set the HTTP status code using integer values or the
THTTPStatus enum:Res.Status(400); // Bad Request
Res.Status(THTTPStatus.NoContent);
- ContentType: Set custom content type headers if you are not returning standard JSON:
Res.ContentType('text/html').Send('<h1>HTML Content</h1>');
Structured Error Handling (EHorseException)
To return error responses with custom HTTP statuses and error details, raise EHorseException. The framework captures this exception and formats it as a structured JSON error response:
uses Horse.Exception, Horse.Commons;
procedure GetProduct(Req: THorseRequest; Res: THorseResponse; Next: TProc);
var
LId: Integer;
LProduct: TProduct;
begin
LId := Req.Params.Field('id').AsInteger;
if LId <= 0 then
raise EHorseException.New
.Status(THTTPStatus.BadRequest)
.Error('Invalid product ID');
LProduct := FindProduct(LId);
if not Assigned(LProduct) then
raise EHorseException.New
.Status(THTTPStatus.NotFound)
.Error('Product not found')
.Code(4041)
.Detail('The requested product does not exist in our catalog.');
Res.Send(LProduct);
end;
When EHorseException is raised, it automatically serializes to a clean JSON response containing fields like error, code, and detail.
1---2name: horse-request-response3description: Guide to interacting with THorseRequest (body, query, params, headers) and THorseResponse (Send, Status, ContentType).4---56# Horse Request & Response78## THorseRequest (Reading Request Data)9The `THorseRequest` object contains all details of the incoming HTTP request.1011* **Body**: To read the raw text payload, use `Req.Body`. If the `Jhonson` middleware is active, you can read the parsed JSON directly:12 ```pascal13 var14 LBody: TJSONObject;15 begin16 LBody := Req.Body<TJSONObject>;17 end;18 ```19* **Params**: For path parameters (defined with `:name`), use `Req.Params.Items['name']` (or `Req.Params['name']`).20* **Query**: For query parameters (e.g., `?page=1&limit=10`), use `Req.Query.Items['page']` (or `Req.Query['page']`).21* **Headers**: Read request headers using `Req.Headers.Items['Authorization']`.2223---2425## Safe Parameter Parsing & Validation (THorseCoreParamField)26Instead of accessing raw string dictionary values (e.g., `Req.Params['id']`) and converting them manually, always prefer using the `.Field()` method to obtain a `THorseCoreParamField`. This provides type-safe conversions and declarative parameter validation:2728* **Type Conversion**: Convert parameters to the target type without manually calling `StrToInt` or `StrToBool`:29 ```pascal30 var31 LId: Integer;32 LActive: Boolean;33 LDate: TDateTime;34 begin35 LId := Req.Params.Field('id').AsInteger;36 LActive := Req.Query.Field('active').AsBoolean;37 LDate := Req.Query.Field('since').AsISO8601DateTime;38 end;39 ```40* **Required Check**: Automatically halt execution and return a 400 Bad Request with a custom error message if the parameter is missing:41 ```pascal42 var43 LEmail: string;44 begin45 // Automatically raises EHorseException if 'email' query param is empty46 LEmail := Req.Query.Field('email').Required.RequiredMessage('The "email" parameter is required.').AsString;47 end;48 ```49* **Supported Converters**: `AsInteger`, `AsInt64`, `AsBoolean`, `AsFloat`, `AsCurrency`, `AsDateTime`, `AsISO8601DateTime`, `AsStream` (for multipart uploads), and `AsString`.5051---5253## Cookies Management54Horse provides a provider-agnostic, typed API to read cookies from requests and write them back in responses (RFC 6265 compliant).5556* **Reading Cookies**: Read incoming cookies safely using the `.Field()` helper:57 ```pascal58 var59 LSessionToken: string;60 begin61 LSessionToken := Req.Cookie.Field('session_token').AsString;62 end;63 ```6465* **Writing Cookies (Set-Cookie)**: Write response cookies using `Res.Cookie` and configure properties fluently:66 ```pascal67 uses Horse.Core.Cookie;6869 procedure SetCookieHandler(Req: THorseRequest; Res: THorseResponse; Next: TProc);70 begin71 // Creates, registers, and configures the cookie fluently (XE7 compatible)72 Res.Cookie('session_id', 'xyz789')73 .Path('/')74 .HttpOnly(True)75 .Secure(True)76 .SameSite(TSameSite.ssLax);7778 Res.Send('Cookie has been set');79 end;80 ```8182---8384## THorseResponse (Sending HTTP Responses)85The `THorseResponse` object is used to build and send the HTTP response back to the client.8687* **Send**: Returns text or objects. It supports method chaining:88 ```pascal89 // Sending simple text with Status 200 (OK)90 Res.Send('Success');91 92 // Setting Status 201 (Created) and sending an object (MUST set status BEFORE calling Send)93 Res.Status(THTTPStatus.Created).Send<TJSONObject>(LJson);94 ```95* **Status**: Set the HTTP status code using integer values or the `THTTPStatus` enum:96 ```pascal97 Res.Status(400); // Bad Request98 Res.Status(THTTPStatus.NoContent);99 ```100* **ContentType**: Set custom content type headers if you are not returning standard JSON:101 ```pascal102 Res.ContentType('text/html').Send('<h1>HTML Content</h1>');103 ```104105---106107## Structured Error Handling (EHorseException)108To return error responses with custom HTTP statuses and error details, raise `EHorseException`. The framework captures this exception and formats it as a structured JSON error response:109110```pascal111uses Horse.Exception, Horse.Commons;112113procedure GetProduct(Req: THorseRequest; Res: THorseResponse; Next: TProc);114var115 LId: Integer;116 LProduct: TProduct;117begin118 LId := Req.Params.Field('id').AsInteger;119 if LId <= 0 then120 raise EHorseException.New121 .Status(THTTPStatus.BadRequest)122 .Error('Invalid product ID');123124 LProduct := FindProduct(LId);125 if not Assigned(LProduct) then126 raise EHorseException.New127 .Status(THTTPStatus.NotFound)128 .Error('Product not found')129 .Code(4041)130 .Detail('The requested product does not exist in our catalog.');131132 Res.Send(LProduct);133end;134```135When `EHorseException` is raised, it automatically serializes to a clean JSON response containing fields like `error`, `code`, and `detail`.