Oihana PHP Arango

HttpTransport

HTTP transport used by the ArangoDB client.

Wraps a Guzzle Client and composes it with three policies:

  • HostRing — round-robin failover over the configured endpoints,
  • RetryPolicy — capped exponential back-off on transient errors,
  • ClientOptions — base configuration (auth, timeout, connection mode, target database, …).

The transport is intentionally low-level: it speaks JSON, returns HttpResponse value objects, and never throws non-Arango exceptions — every failure surfaces as a subclass of ArangoException.

The Guzzle client can be injected for testing (with a MockHandler).

Runtime auth state — the transport itself is not readonly because login(), setBearerToken() and setBasicAuth() mutate the active auth scheme + credentials between requests ($current* properties), and the 401 auto-refresh path inside request() mutates them too. The injected ClientOptions remains immutable; the runtime auth state is seeded from it at construction time and becomes the source of truth afterwards.

Tags
author

Marc Alcaraz (ekameleon)

since
1.0.0

Table of Contents

Constants

ARANGO_DIRTY_READ_HEADER  : string = 'x-arango-allow-dirty-read'
Header that opts a request into ArangoDB's dirty-read mode on a cluster deployment. When the transport's {@see ClientOptions::$allowDirtyRead} is true, every outbound request carries this header set to {@see \oihana\enums\Boolean::TRUE} so the coordinator may serve reads from any follower.
ARANGO_TRX_ID_HEADER  : string = 'x-arango-trx-id'
Header that scopes a request to a running streaming transaction.
DATABASE_PATH_PREFIX  : string = '/_db/'
URL prefix used to scope a request to a specific database (ArangoDB convention).

Properties

$hostRing  : HostRing
Round-robin ring over the configured server endpoints.
$options  : ClientOptions
$retryPolicy  : RetryPolicy
Retry policy applied on transient failures.
$activeTransactionId  : string|null
Active streaming-transaction id, used as a fallback by {@see request()} when no explicit `$transactionId` is passed.
$currentAuthType  : string
Currently active auth scheme (`BASIC` or `JWT`). Seeded from {@see ClientOptions::$authType}; mutated by {@see setBearerToken()}, {@see setBasicAuth()}, {@see login()} and the auto-refresh on 401.
$currentBasicPassword  : string|null
Currently active basic-auth password. Seeded from {@see ClientOptions::$password}. See {@see $currentBasicUser}.
$currentBasicUser  : string|null
Currently active basic-auth user. Seeded from {@see ClientOptions::$user}; mutated by {@see setBasicAuth()}. Kept around even when running in JWT mode, so the transport can refresh the JWT on 401 by re-logging in.
$currentBearerToken  : string|null
Currently active bearer token (JWT). Seeded from {@see ClientOptions::$token}; mutated by {@see setBearerToken()}, {@see login()} and the auto-refresh on 401.
$httpClient  : Client
Underlying Guzzle HTTP client.
$refreshingAuth  : bool
Guard against re-entering the 401 refresh path from inside the refresh request itself (which would loop forever).

Methods

__construct()  : mixed
login()  : string
Authenticates against ArangoDB by posting `{username, password}` to the unauthenticated `/_open/auth` endpoint and stores the returned JWT in the transport's runtime auth state. Returns the JWT for the caller's convenience (e.g. when it needs to forward it to another client / cache it elsewhere).
request()  : HttpResponse
Sends an HTTP request to the ArangoDB server and returns the parsed response.
setBasicAuth()  : void
Switches the transport to Basic auth with the given credentials.
setBearerToken()  : void
Switches the transport to JWT/Bearer mode with the given token.
withActiveTransactionId()  : mixed
Runs `$callback` with `$id` installed as the active streaming transaction id on this transport, then restores the previous value (including on exception).
buildAuthHeader()  : string|null
Builds the Authorization header value from the current runtime auth state (which is seeded from {@see ClientOptions} at construction time and mutated by {@see setBearerToken()} / {@see setBasicAuth()} / {@see login()} / the auto-refresh on 401).
buildUrl()  : string
Builds the absolute URL for a given API path.
decodeBody()  : mixed
Decodes a JSON body string into PHP, returning null when the body is empty or cannot be parsed.
defaultHeaders()  : array<string, string>
Builds the default headers attached to every request (auth + content negotiation + connection mode).
guzzleConfig()  : array<string, mixed>
Builds the static Guzzle configuration shared across all requests.
mapBadResponse()  : ArangoException
Wraps a Guzzle 4xx/5xx response into the appropriate ArangoException subclass (Conflict / Maintenance / generic Http).
mapResponse()  : HttpResponse
Wraps a successful Guzzle response (2xx) into an {@see HttpResponse} value object.
mergeOptions()  : array<string, mixed>
Merges per-request options (body, query string, headers) into the shape expected by Guzzle's `request()` method.

Constants

ARANGO_DIRTY_READ_HEADER

Header that opts a request into ArangoDB's dirty-read mode on a cluster deployment. When the transport's {@see ClientOptions::$allowDirtyRead} is true, every outbound request carries this header set to {@see \oihana\enums\Boolean::TRUE} so the coordinator may serve reads from any follower.

private string ARANGO_DIRTY_READ_HEADER = 'x-arango-allow-dirty-read'
Tags
see
https://docs.arangodb.com/stable/deploy/cluster/operation/#read-from-followers

Properties

$hostRing read-only

Round-robin ring over the configured server endpoints.

public HostRing $hostRing

$activeTransactionId

Active streaming-transaction id, used as a fallback by {@see request()} when no explicit `$transactionId` is passed.

private string|null $activeTransactionId = null

Set by withActiveTransactionId() (which always reverts the previous value in a finally block, including on exception), so this slot is never left dangling pointing at a transaction that has been committed or aborted.

The per-request $transactionId parameter of request() still wins when both are set — the active id is only the fallback for operations that don't pass one explicitly (e.g. a Collection::insert() call invoked from inside a Transaction::step() callback).

$currentAuthType

Currently active auth scheme (`BASIC` or `JWT`). Seeded from {@see ClientOptions::$authType}; mutated by {@see setBearerToken()}, {@see setBasicAuth()}, {@see login()} and the auto-refresh on 401.

private string $currentAuthType

$currentBasicPassword

Currently active basic-auth password. Seeded from {@see ClientOptions::$password}. See {@see $currentBasicUser}.

private string|null $currentBasicPassword

$currentBasicUser

Currently active basic-auth user. Seeded from {@see ClientOptions::$user}; mutated by {@see setBasicAuth()}. Kept around even when running in JWT mode, so the transport can refresh the JWT on 401 by re-logging in.

private string|null $currentBasicUser

$currentBearerToken

Currently active bearer token (JWT). Seeded from {@see ClientOptions::$token}; mutated by {@see setBearerToken()}, {@see login()} and the auto-refresh on 401.

private string|null $currentBearerToken

$httpClient read-only

Underlying Guzzle HTTP client.

private Client $httpClient

$refreshingAuth

Guard against re-entering the 401 refresh path from inside the refresh request itself (which would loop forever).

private bool $refreshingAuth = false

Methods

__construct()

public __construct(ClientOptions $options[, Client|null $httpClient = null ][, RetryPolicy|null $retryPolicy = null ][, HostRing|null $hostRing = null ]) : mixed
Parameters
$options : ClientOptions

Connection options (auth, timeout, endpoints, …).

$httpClient : Client|null = null

Optional Guzzle client; defaults to a new client built from $options. Inject a mocked client for tests.

$retryPolicy : RetryPolicy|null = null

Optional retry policy; defaults to RetryPolicy with built-in defaults.

$hostRing : HostRing|null = null

Optional host ring; defaults to a ring built from $options->endpoints.

login()

Authenticates against ArangoDB by posting `{username, password}` to the unauthenticated `/_open/auth` endpoint and stores the returned JWT in the transport's runtime auth state. Returns the JWT for the caller's convenience (e.g. when it needs to forward it to another client / cache it elsewhere).

public login(string $user, string $password) : string

The basic credentials are stored alongside the JWT so the transport can refresh it on 401 by re-logging in.

Parameters
$user : string
$password : string
Tags
throws
ArangoException

When the request fails (network or 4xx/5xx response).

Return values
string

The JWT returned by the server.

request()

Sends an HTTP request to the ArangoDB server and returns the parsed response.

public request(string $method, string $path[, array<string, mixed>|string|null $body = null ][, array<string, mixed> $query = [] ][, array<string, string> $headers = [] ][, string|null $databaseOverride = null ][, string|null $transactionId = null ]) : HttpResponse

On transient failures (network errors, write-write conflict, cluster maintenance, …) the request is retried according to the configured RetryPolicy. When multiple endpoints are configured the ring cursor is advanced between attempts.

Parameters
$method : string

HTTP verb (GET, POST, …).

$path : string

API path beginning with /. Prefixed with /_db/{database} according to $databaseOverride.

$body : array<string, mixed>|string|null = null

Request body. When an array is passed the transport serialises it as JSON; when a string is passed it is sent verbatim as the raw HTTP body (use this for /_api/import JSON Lines payloads — caller is then responsible for the Content-Type header). Pass null for verbs without a body.

$query : array<string, mixed> = []

Query string parameters.

$headers : array<string, string> = []

Extra headers (merged with the per-request defaults).

$databaseOverride : string|null = null

Controls the /_db/{name} prefix:

  • null (default) — use $options->database when set, otherwise no prefix;
  • '' (empty string) — no prefix (global server route, e.g. /_api/database);
  • non-empty — use the given database name (overrides the options).
$transactionId : string|null = null

Optional streaming transaction id to scope this request to. When non-null, the x-arango-trx-id: {id} header is added so the server attaches the operation to the running transaction. Passed explicitly rather than via $headers to keep the transaction surface typed and testable.

Tags
throws
ArangoException

When the request fails and the retry policy is exhausted.

Return values
HttpResponse

setBasicAuth()

Switches the transport to Basic auth with the given credentials.

public setBasicAuth(string $user, string $password) : void

Subsequent requests carry Authorization: basic base64(user:password). Any bearer token previously set is cleared so the basic credentials take effect.

Parameters
$user : string
$password : string

setBearerToken()

Switches the transport to JWT/Bearer mode with the given token.

public setBearerToken(string|null $token) : void

Subsequent requests carry Authorization: bearer <token>. The basic credentials (if any) are kept around so the transport can refresh the JWT on 401 by re-logging in.

Pass null to revert to the basic credentials (or to anonymous mode when none are configured).

Parameters
$token : string|null

JWT to send on subsequent requests.

withActiveTransactionId()

Runs `$callback` with `$id` installed as the active streaming transaction id on this transport, then restores the previous value (including on exception).

public withActiveTransactionId(string|null $id, callable(): mixed $callback) : mixed

While the callback runs, any request() that does not pass an explicit $transactionId falls back to $id — so a Collection::insert() (or any other plain CRUD call) invoked from inside the callback is automatically scoped to the running transaction. This is how Transaction::step() makes the transactional context transparent to existing code that does not know about transactions.

Nesting is supported: an inner withActiveTransactionId() temporarily overrides the outer id, and reverts it on exit.

Pass null for $id to explicitly run a callback outside any current transaction (e.g. to make a side-channel admin call that must not be part of the user's transaction).

Parameters
$id : string|null

Transaction id to scope the callback to (or null to suspend any active scope).

$callback : callable(): mixed

User-provided block.

Tags
throws
Throwable

Whatever the callback throws (re-thrown after the previous transaction id is restored).

Return values
mixed

The value returned by $callback.

buildAuthHeader()

Builds the Authorization header value from the current runtime auth state (which is seeded from {@see ClientOptions} at construction time and mutated by {@see setBearerToken()} / {@see setBasicAuth()} / {@see login()} / the auto-refresh on 401).

private buildAuthHeader() : string|null
Return values
string|null

The header value (e.g. Basic dXNlcjpwYXNz or Bearer eyJ…), or null when no credentials are configured (anonymous mode).

buildUrl()

Builds the absolute URL for a given API path.

private buildUrl(string $endpoint, string $path[, string|null $databaseOverride = null ]) : string

The /_db/{database} prefix is applied based on $databaseOverride:

  • null falls back to $options->database,
  • the empty string skips the prefix entirely (global server route),
  • any other value is used as the database name verbatim.
Parameters
$endpoint : string

Base endpoint URL (already normalised by HostRing).

$path : string

API path (with or without a leading /).

$databaseOverride : string|null = null

Optional database scope override (see above).

Return values
string

Absolute URL ready to be passed to the Guzzle client.

decodeBody()

Decodes a JSON body string into PHP, returning null when the body is empty or cannot be parsed.

private decodeBody(string $raw) : mixed
Parameters
$raw : string

Raw response body.

Return values
mixed

Decoded value (array / scalar / null) or null on parse failure.

defaultHeaders()

Builds the default headers attached to every request (auth + content negotiation + connection mode).

private defaultHeaders() : array<string, string>
Return values
array<string, string>

guzzleConfig()

Builds the static Guzzle configuration shared across all requests.

private guzzleConfig() : array<string, mixed>

Default headers are intentionally applied per request (in mergeOptions()) rather than at client construction time, so that an externally injected Client (for instance a mocked one in tests) still receives the transport's auth + content negotiation headers.

Return values
array<string, mixed>

mapBadResponse()

Wraps a Guzzle 4xx/5xx response into the appropriate ArangoException subclass (Conflict / Maintenance / generic Http).

private mapBadResponse(BadResponseException $e) : ArangoException
Parameters
$e : BadResponseException

The Guzzle exception raised on a 4xx/5xx response.

Return values
ArangoException

A typed Arango exception ready to be thrown by request().

mapResponse()

Wraps a successful Guzzle response (2xx) into an {@see HttpResponse} value object.

private mapResponse(ResponseInterface $response) : HttpResponse
Parameters
$response : ResponseInterface

PSR-7 response from Guzzle.

Return values
HttpResponse

Decoded response carrying status, headers, body and raw payload.

mergeOptions()

Merges per-request options (body, query string, headers) into the shape expected by Guzzle's `request()` method.

private mergeOptions(array<string, mixed>|string|null $body, array<string, mixed> $query, array<string, string> $headers) : array<string, mixed>

The body type drives the wire encoding:

  • array — sent as JSON via GuzzleOption::JSON (Guzzle adds the Content-Type: application/json header).
  • string — sent verbatim via GuzzleOption::BODY (used for /_api/import JSON Lines payloads; the caller is responsible for the Content-Type header).
  • null — no body emitted.
Parameters
$body : array<string, mixed>|string|null
$query : array<string, mixed>
$headers : array<string, string>
Return values
array<string, mixed>
On this page

Search results