Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Catalog · How the catalog works

Random project

request-fp

Zero‑memory‑leak, high‑level HTTP client for Free Pascal. Built on top of FPC's HTTP stack with a clean API and zero boilerplate.

View on GitHub

Anyone may press Interesting, signed in or not. It helps others find this project.

Member rating

No ratings yet.

Sign in to rate this project.

README

Request-FP

Request-FP — easy HTTP for Free Pascal

An easy, memory-safe HTTP client for Free Pascal. Request-FP wraps FPC's HTTP stack with a small API, automatic cleanup, and no application-level dependencies.

Start here

Add src to your unit search path and make a request:

pascal
uses Request;

var
  Response: TResponse;
begin
  Response := Http.Get('https://api.example.com/users');
  Response.RaiseForStatus;
  WriteLn(Response.Text);
end.

There is no client to create or free. TResponse cleans itself up.

Use the stateless Http API for one-off requests. Use THttpSession when requests need to share a base URL, headers, or cookies.

Common requests

Query parameters

KV is the short syntax for a header, query parameter, form field, or multipart field:

pascal
Response := Http.GetWithParams('https://api.example.com/search', [
  KV('q', 'free pascal'),
  KV('page', '2')
]);

Request-FP percent-encodes names and values as UTF-8.

Headers and query parameters together

pascal
Response := Http.Get('https://api.example.com/search',
  [KV('Authorization', 'Bearer ' + Token)],
  [KV('q', 'free pascal')]);

The second array is headers and the third is query parameters. TKeyValue.Create(...) remains available for existing code.

Form data

pascal
Response := Http.PostForm('https://api.example.com/login', [
  KV('email', 'ada@example.com'),
  KV('password', Password)
]);

PostForm performs the form encoding and sets application/x-www-form-urlencoded. Use Http.Post when the body is already encoded or is another content type.

JSON

Post a JSON string:

pascal
Response := Http.PostJSON(
  'https://api.example.com/users',
  '{"name":"Ada"}'
);

Or pass an existing TJSONData value directly:

pascal
uses Request, fpjson;

var
  Body: TJSONObject;
begin
  Body := TJSONObject.Create;
  try
    Body.Add('name', 'Ada');
    Response := Http.PostJSON('https://api.example.com/users', Body);
  finally
    Body.Free;
  end;
end;

Request-FP reads JSON responses lazily:

pascal
WriteLn(Response.JSON.FindPath('user.name').AsString);

Response owns the parsed value returned by Response.JSON. Do not free that value yourself. Invalid JSON raises ERequestError with a JSON Parse Error message.

Multipart file upload

pascal
Response := Http.PostMultipart('https://api.example.com/upload',
  [KV('description', 'avatar')],
  [KV('file', 'avatar.png')]);

The key in the files array is the form field name; the value is the local file path.

Handling success and errors

Choose the style that fits your program.

Exceptions for transport errors

Normal methods raise ERequestError for network, TLS, and request failures. Inspect the response or opt in to raising for a non-2xx status:

pascal
try
  Response := Http.Get('https://api.example.com/users/42');
  Response.RaiseForStatus;
  WriteLn(Response.Text);
except
  on E: ERequestError do
    WriteLn(E.Message);
end;

You can also branch without raising:

pascal
if Response.OK then
  WriteLn(Response.Text)
else
  WriteLn('HTTP status: ', Response.StatusCode);

Response.OK and Response.IsSuccessStatus are true for status codes 200 through 299.

No exceptions

Every Try* method catches request exceptions:

pascal
Result := Http.TryGet('https://api.example.com/users/42');
if Result.OK then
  WriteLn(Result.Response.Text)
else if not Result.Success then
  WriteLn('Request failed: ', Result.Error)
else
  WriteLn('HTTP status: ', Result.Response.StatusCode);
  • Result.Success means the HTTP exchange completed, even if the server returned 404 or 500.
  • Result.OK means the exchange completed and the status is 2xx.
  • TryGet, TryGetWithParams, TryPost, TryPostForm, TryPostJSON, TryPut, TryDelete, and TryPostMultipart do not raise request exceptions.

Sessions

Add Request.Session when calls should share configuration or cookies:

pascal
uses Request, Request.Session;

var
  Session: THttpSession;
  Response: TResponse;
begin
  Session.SetBaseURL('https://api.example.com');
  Session.SetHeader('Authorization', 'Bearer ' + Token);

  Response := Session.Get('/profile');
  if Response.OK then
    WriteLn(Response.Text);
end.

Sessions initialize and clean themselves up automatically. You do not need to call Session.Init; call it only when you want to reset an existing session to its defaults.

The base URL works with or without a trailing slash, and paths work with or without a leading slash.

Post JSON with the same convenience as the stateless API:

pascal
Response := Session.PostJSON('/profile', '{"displayName":"Ada"}');

See the session guide for cookies, timeouts, and the complete API.

Installation

  1. Copy src/Request.pas and, if needed, src/Request.Session.pas into your project, or clone this repository.
  2. Add the src directory to the project's unit search path.
  3. Add Request to your uses clause.

Requirements:

  • Free Pascal 3.2.2+ or Lazarus 4.8+
  • Windows or Linux
  • OpenSSL libraries for HTTPS

On Linux, install the distribution's OpenSSL development package. On Windows, the OpenSSL DLL architecture must match the executable architecture. Request-FP v1.3.0 automatically handles FPC 3.2.2's OpenSSL 3 DLL-name issue and retains its OpenSSL 1.1 fallback; applications do not need to patch FPC. If HTTPS setup fails, run examples/ssl_debug and follow the SSL/HTTPS guide.

API at a glance

pascal
// Requests
Http.Get(URL)
Http.GetWithParams(URL, Params)
Http.Post(URL, Body)
Http.PostForm(URL, Fields)
Http.PostJSON(URL, JSON)
Http.Put(URL, Body)
Http.Delete(URL)
Http.PostMultipart(URL, Fields, Files)

// Response
Response.StatusCode
Response.Text
Response.JSON
Response.OK
Response.HeaderValue('Content-Type')
Response.RaiseForStatus
Response.SaveToFile('output.dat')

Most methods also have header/query-parameter overloads and exception-free Try* counterparts. See the API reference for exact signatures.

Documentation and examples

Build all examples

The repository includes scripts that compile every Lazarus example in Release mode and collect the executables in example-bin/.

Windows PowerShell:

powershell
.\build-examples.ps1

If script execution is disabled by local policy:

powershell
powershell -ExecutionPolicy Bypass -File .\build-examples.ps1

Linux or Git Bash:

bash
bash ./build-examples.sh

Both scripts require lazbuild on PATH. They discover all .lpi projects under examples/, skip Lazarus backup directories, and clean example-bin/ before compiling. The generated directory is ignored by Git.

Run an example after building:

powershell
.\example-bin\easy_get.exe
bash
./example-bin/easy_get

Testing

Build the suite with Lazarus or:

bash
lazbuild --build-mode=Release tests/TestRunner.lpi
tests/TestRunner.exe -a --format=plain

On Linux, run tests/TestRunner. CI starts tests/http_fixture.py and points the suite at that local service, so CI does not depend on a public HTTP test service. A direct local run without REQUEST_FP_TEST_BASE_URL falls back to https://httpbin.org and therefore requires network access.

Contributing

See CONTRIBUTING.md.

License

Request-FP is available under the MIT License.