HTTP
Overview
The SDK does not talk to the EFL Leasing Online API directly. Instead, it uses a small HTTP abstraction that separates:
Config– base URL and authentication settings.HttpClientInterface– your HTTP library (Guzzle, Symfony HttpClient, custom).EflHttpClient– high-level helper that knows how to build URLs, apply headers and map errors.HttpResponse– simple value object used by the SDK.
This section describes these building blocks so you can plug in your own HTTP client implementation safely.
HttpClientInterface
HttpClientInterface is the only contract the SDK needs in order to perform HTTP requests:
use Imoli\EflLeasingSdk\Exception\HttpException;
use Imoli\EflLeasingSdk\Http\HttpClientInterface;
use Imoli\EflLeasingSdk\Http\HttpResponse;
interface HttpClientInterface
{
/**
* @param non-empty-string $method HTTP method, e.g. GET, POST.
* @param non-empty-string $url Absolute URL including scheme and host.
* @param array<string, string> $headers
* @param string|null $body
*
* @throws HttpException When the request fails at transport level.
*/
public function request(
string $method,
string $url,
array $headers = [],
?string $body = null,
): HttpResponse;
}
The implementation is responsible for:
- Executing the HTTP request with the given method, URL, headers and optional body.
- Returning a
HttpResponseobject for all requests (even when the status code is 4xx/5xx). - Throwing
HttpExceptionwhen a transport-level error occurs (network failures, timeouts, low-level library errors).
HttpResponse
HttpResponse is a small immutable value object used by the SDK and exposed by low-level API clients:
use Imoli\EflLeasingSdk\Http\HttpResponse;
final class HttpResponse
{
public function __construct(int $statusCode, array $headers, string $body);
public function getStatusCode(): int;
/** @return array<string, string> */
public function getHeaders(): array;
public function getBody(): string;
}
statusCode– numeric HTTP status code returned by the server.headers– flattened associative array of response headers.body– raw response body as a string.
High-level methods on EflClient usually deserialize the body for you.
Low-level clients expose HttpResponse so you can inspect and parse the payload manually when needed.
EflHttpClient
EflHttpClient connects your Config and HttpClientInterface implementation with the EFL Leasing Online API semantics:
use Imoli\EflLeasingSdk\Config;
use Imoli\EflLeasingSdk\Http\EflHttpClient;
use Imoli\EflLeasingSdk\Http\HttpClientInterface;
use Imoli\EflLeasingSdk\Http\HttpResponse;
use Imoli\EflLeasingSdk\Http\RequestLoggerInterface;
final class EflHttpClient
{
public function __construct(
Config $config,
HttpClientInterface $httpClient,
?RequestLoggerInterface $logger = null,
);
/** @return HttpResponse */
public function requestWithApiKey(
string $method,
string $path,
array $query = [],
array $headers = [],
?string $body = null,
): HttpResponse;
/** @return HttpResponse */
public function requestWithBearerToken(
string $method,
string $path,
string $token,
array $query = [],
array $headers = [],
?string $body = null,
): HttpResponse;
/** @return HttpResponse */
public function request(
string $method,
string $path,
array $query = [],
array $headers = [],
?string $body = null,
): HttpResponse;
}
Key responsibilities:
- URL building – combines
Config::getBaseUrl()with relative paths such as/lon/api/v1/...and serializes query parameters. - Authentication:
requestWithApiKey()adds theApiKeyheader fromConfig.requestWithBearerToken()adds theAuthorization: Bearer ...header.
- Logging (optional) – calls
RequestLoggerInterfacebefore and after the request. - Error mapping – for HTTP status codes
>= 400it throwsApiExceptionwith parsedProblemDetailswhen available.
You normally do not instantiate EflHttpClient directly.
It is created inside EflClient and in low-level API clients.
Built-in adapters
The SDK ships with ready-made adapters for popular HTTP libraries.
They all implement HttpClientInterface, so you can swap them without changing the rest of your code.
GuzzleHttpAdapter
use GuzzleHttp\Client as GuzzleClient;
use Imoli\EflLeasingSdk\Http\Adapter\GuzzleHttpAdapter;
use Imoli\EflLeasingSdk\Http\HttpClientInterface;
$guzzle = new GuzzleClient([
'timeout' => 30,
'connect_timeout' => 10,
]);
/** @var HttpClientInterface $httpClient */
$httpClient = new GuzzleHttpAdapter($guzzle);
- Requires the
guzzlehttp/guzzlepackage. - Disables automatic exceptions on 4xx/5xx (
http_errorsis set tofalse) so thatEflHttpClientcan handle API errors consistently.
SymfonyHttpAdapter
use Imoli\EflLeasingSdk\Http\Adapter\SymfonyHttpAdapter;
use Symfony\Component\HttpClient\HttpClient;
$symfonyClient = HttpClient::create();
$httpClient = new SymfonyHttpAdapter($symfonyClient);
- Requires the
symfony/http-clientpackage. - Adapts Symfony's response object to
HttpResponse, flattening multi-value headers.
NativeHttpClient
use Imoli\EflLeasingSdk\Http\HttpClientInterface;
use Imoli\EflLeasingSdk\Http\NativeHttpClient;
/** @var HttpClientInterface $httpClient */
$httpClient = new NativeHttpClient();
NativeHttpClient is a minimal placeholder implementation.
At the moment it throws HttpException for all calls and is intended only as a starting point.
For real integrations you should:
- Use the Guzzle or Symfony adapters, or
- Provide your own robust implementation of
HttpClientInterface.
Custom adapters
If you use a different HTTP client library, implement HttpClientInterface yourself.
As a quick checklist:
- Do not throw exceptions on HTTP 4xx/5xx – always return a
HttpResponse. - Do throw
HttpExceptionfor network/transport errors or misconfiguration. - Normalize response headers to a simple
array<string, string>. - Preserve the raw response body exactly as returned by the server.
Once you have an implementation, pass it to EflClient together with Config:
use Imoli\EflLeasingSdk\Config;
use Imoli\EflLeasingSdk\EflClient;
use Imoli\EflLeasingSdk\Http\HttpClientInterface;
/** @var HttpClientInterface $httpClient */
$config = Config::sandbox('your-sandbox-api-key');
$client = new EflClient($config, $httpClient);