Browse documentation

Session API guide

On this page

Request.Session provides a stateful HTTP client for calls that share a base URL, headers, cookies, or a connection.

Use the stateless Http API for one-off calls. Use THttpSession for a login flow or a group of calls to the same service.

Quick start

uses SysUtils, Request, Request.Session;

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

  Response := Session.Get('/profile');
  Response.RaiseForStatus;
  WriteLn(Response.Text);
end.

THttpSession is an advanced record. It initializes and cleans itself up automatically, so there is no required constructor, Init, Free, or try..finally block.

Session.Init is retained for compatibility and now means “reset this session to its defaults.” It is optional for a newly declared session.

Base URLs

Set a base URL once and pass relative paths:

Session.SetBaseURL('https://api.example.com/v1');
Response := Session.Get('/users');

Slash handling is automatic. These combinations all produce the same URL:

Session.SetBaseURL('https://api.example.com/v1');
Session.Get('users');

Session.SetBaseURL('https://api.example.com/v1/');
Session.Get('/users');

An absolute URL passed to a request method bypasses the base URL.

Headers

Headers set on a session are sent on every request:

Session.SetBearerToken(Token);           // Authorization: Bearer ...
Session.SetBasicAuth('user', 'secret');  // or Authorization: Basic ...
Session.SetHeader('Accept-Language', 'en-AU');
Response := Session.Get('/profile');

Authorization is not sent when a redirect goes to a different host.

ClearHeaders removes custom headers and restores the default Accept: application/json header.

The session uses Request-FP/<version> as its default user agent. Override it with:

Session.SetUserAgent('MyApp/1.0');

JSON

Post a JSON string:

Response := Session.PostJSON('/users', '{"name":"Ada"}');

Or pass a TJSONData value:

uses Request, Request.Session, fpjson;

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

The caller retains ownership of a JSON value passed to PostJSON. PutJSON and PatchJSON (and TryPutJSON / TryPatchJSON) work the same way.

For other content types, use Post or Put directly:

Response := Session.Post('/submit', 'name=Ada',
  'application/x-www-form-urlencoded');

Per-request headers and parameters

Session headers apply to every call. Add or override headers for one call with Get(URL, Headers) or the general Send:

Response := Session.Get('/report', [KV('Accept', 'text/csv')]);
Response := Session.GetWithParams('/search', [KV('q', 'pascal')]);

// Method, URL, Body, ContentType, Headers, Params
Response := Session.Send('PATCH', '/users/42', '{"active":false}',
  'application/json', [KV('If-Match', ETag)], []);

Forms and uploads

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

Response := Session.PostMultipart('/upload',
  [KV('description', 'avatar')],
  [KV('file', 'avatar.png')]);

Downloads

Download and GetToStream stream the body to a file or stream, with session headers and cookies applied:

Response := Session.Download('/reports/2026.pdf', 'report.pdf');
Response := Session.Download('/backup.zip', 'backup.zip', @ShowProgress);
Response := Session.GetToStream('/export.csv', MyStream);

The rules match Http.Download: only a 2xx body is saved, the file is replaced only when complete, and the error body is in Response.Text. TryDownload and TryGetToStream return TRequestResult.

Cookies

Cookies received in Set-Cookie headers are stored and sent by later calls:

You can also manage them directly:

Session.SetCookie('session_id', 'abc123');
WriteLn(Session.GetCookie('session_id'));
Session.ClearCookies;

Timeouts

The default timeout is 30 seconds. Values are milliseconds:

Session.SetTimeout(10000);

The new timeout applies to the current connection and later calls. A request that exceeds it raises ETimeoutError. The connect timeout is separate:

Session.SetConnectTimeout(5000);  // default 3000

Proxy

Session.SetProxy('proxy.local', 3128, 'user', 'secret');
Session.SetProxy('', 0);  // remove

Like Http.SetProxy, this covers http:// URLs only; https:// requests raise ERequestError while a proxy is set.

Retries

Sessions retry GET, HEAD, PUT, and DELETE on network errors, 429, and 503 (2 retries, 250 ms then 500 ms), like the stateless API:

Session.SetRetry(5, 100);  // more patient
Session.SetRetry(0, 0);    // disable

Reading a response

Session methods return the same TResponse as the stateless API:

if Response.OK then
begin
  WriteLn(Response.Text);
  WriteLn(Response.HeaderValue('Content-Type'));
end;

The response owns its parsed Response.JSON value; do not free it manually. See the Request API reference for all response helpers.

Error handling

Session methods behave like the stateless API:

Result := Session.TryGet('/profile');
if Result.OK then
  WriteLn(Result.Response.Text)
else if Result.Success then
  WriteLn('HTTP ', Result.Response.StatusCode)
else
  WriteLn('Failed: ', Result.Error);
try
  Response := Session.Get('/profile');
  Response.RaiseForStatus;
except
  on E: ERequestError do
    WriteLn('Request failed: ', E.Message);
end;

Before v1.3.1, session methods raised for some non-error statuses (for example Get on 201 or 404) and Post could raise FPC exception types.

API reference

THttpSession = record
  // Optional reset
  procedure Init;

  // Requests
  function Get(const URL: string): TResponse;
  function Get(const URL: string; const Headers: array of TKeyValue): TResponse;
  function GetWithParams(const URL: string; const Params: array of TKeyValue): TResponse;
  function Post(const URL: string; const Body: string = '';
    const ContentType: string = 'application/x-www-form-urlencoded'): TResponse;
  function PostJSON(const URL: string; const JSON: string): TResponse;
  function PostJSON(const URL: string; const JSON: TJSONData): TResponse;
  function PutJSON(const URL: string; const JSON: string): TResponse;  // also TJSONData
  function PatchJSON(const URL: string; const JSON: string): TResponse; // also TJSONData
  function PostForm(const URL: string; const Fields: array of TKeyValue): TResponse;
  function PostMultipart(const URL: string; const Fields, Files: array of TKeyValue): TResponse;
  function Put(const URL: string; const Body: string = '';
    const ContentType: string = 'application/json'): TResponse;
  function Patch(const URL: string; const Body: string = '';
    const ContentType: string = 'application/json'): TResponse;
  function Delete(const URL: string): TResponse;
  function Head(const URL: string): TResponse;
  function Send(const Method, URL: string; const Body: string;
    const ContentType: string; const Headers: array of TKeyValue;
    const Params: array of TKeyValue): TResponse;

  // Streaming (OnProgress is optional: TProgressProc or TProgressEvent)
  function Download(const URL, FilePath: string; OnProgress): TResponse;
  function GetToStream(const URL: string; Stream: TStream; OnProgress): TResponse;

  // Exception-free: TryGet, TryPost, TryPostJSON, TryPostForm,
  // TryPostMultipart, TryPut, TryPatch, TryDelete, TryHead, TrySend,
  // TryDownload, TryGetToStream (same parameters, return TRequestResult)

  // Configuration
  procedure SetHeader(const Name, Value: string);
  procedure SetCookie(const Name, Value: string);
  procedure SetBaseURL(const URL: string);
  procedure SetUserAgent(const UserAgent: string);
  procedure SetTimeout(Timeout: Integer);
  procedure SetRetry(MaxRetries, BaseDelayMS: Integer);
  procedure SetConnectTimeout(Timeout: Integer);
  procedure SetProxy(const Host: string; Port: Integer;
    const UserName: string = ''; const Password: string = '');
  procedure SetBasicAuth(const UserName, Password: string);
  procedure SetBearerToken(const Token: string);

  // State
  procedure ClearCookies;
  function GetCookie(const Name: string): string;
  procedure ClearHeaders;
end;

TSimpleMap is public for compatibility but is an implementation detail for most users.

HTTPS

Session requests use the same FPC/OpenSSL stack and automatic Windows OpenSSL 3 filename selection as the stateless API. No session-specific TLS configuration is required.

See the SSL/HTTPS guide if setup fails, or OpenSSL version selection for the FPC 3.2.2 compatibility details.