| name | horse-request-response |
|---|---|
| description | Guide to interacting with THorseRequest (body, query, params, headers) and THorseResponse (Send, Status, ContentType). |
The THorseRequest object contains all details of the incoming HTTP request.
- Body: To read the raw text payload, use
Req.Body. If theJhonsonmiddleware is active, you can read the parsed JSON directly:var LBody: TJSONObject; begin LBody := Req.Body<TJSONObject>; end;
- Params: For path parameters (defined with
:name), useReq.Params.Items['name'](orReq.Params['name']). - Query: For query parameters (e.g.,
?page=1&limit=10), useReq.Query.Items['page'](orReq.Query['page']). - Headers: Read request headers using
Req.Headers.Items['Authorization'].
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
StrToIntorStrToBool: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), andAsString.
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.Cookieand 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;
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
THTTPStatusenum: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>');
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.