PHPackages                             dormilich/http-client - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. dormilich/http-client

ActiveLibrary[HTTP &amp; Networking](/categories/http)

dormilich/http-client
=====================

A request/response handler around a PSR-18 HTTP client.

0.2.0(8mo ago)134MITPHPPHP ^8.0

Since Aug 13Pushed 8mo ago1 watchersCompare

[ Source](https://github.com/Dormilich/http-client)[ Packagist](https://packagist.org/packages/dormilich/http-client)[ RSS](/packages/dormilich-http-client/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (4)Versions (4)Used By (0)

HTTP client request/response handlers
=====================================

[](#http-client-requestresponse-handlers)

The purpose of this library is to define handlers around a PSR-18 HTTP client that convert data into a request and a response back into the desired data structure, while being independent of the actual HTTP client implementation.

Installation
------------

[](#installation)

You can install this library via composer:

```
composer require dormilich/http-client

```

To use this library, install you personal choice of a [PSR-18](https://www.php-fig.org/psr/psr-18/)HTTP client and [PSR-17](https://www.php-fig.org/psr/psr-17/) HTTP factories.

HTTP Client
-----------

[](#http-client)

The HTTP client needs to be set up with a PSR-18 HTTP client and a PSR-17 request and stream factory.

```
use Dormilich\HttpClient\Client;

// replace this with the actual implementations
$httpClient = new HttpClient();         // PSR-18
$requestFactory = new RequestFactory(); // PSR-17
$streamFactory = new StreamFactory();   // PSR-17

$client = new Client($httpClient, $requestFactory, $streamFactory);
```

While this may look tedious for manual setup, this becomes easy in most frameworks with dependency injection.

Before sending off the request, the client will apply any default headers that were defined as well as any request modifications (see [Request modification](#request-modification)).

```
use Dormilich\HttpClient\Client;

$client = new Client($httpClient, $requestFactory, $streamFactory);
$client->getHeaders()->add('User-Agent', 'curl/7.64.1');
// all requests will now contain the `User-Agent` header
```

If no data transformer is defined (see [Data transformers](#data-transformers)), it is only possible to send PSR-7 requests. Otherwise, the client will complain that no encoder is defined for the data to be processed and throw a `UnsupportedDataTypeException`.

```
use Dormilich\HttpClient\Client;

$client = new Client($httpClient, $requestFactory, $streamFactory);

$request = new Request('GET', 'https://example.com'); // PSR-7
// $result will contain the response body content
$result = $client->request($request);
```

The client supports the most common HTTP methods as shorthand methods. This requires data encoders to be defined previously.

```
use Dormilich\HttpClient\Client;
use Dormilich\HttpClient\Transformer\JsonEncoder;

$client = new Client($httpClient, $requestFactory, $streamFactory);
$client->addTransformer(new JsonEncoder());

$client->get('https://example.com/item');
$client->post('https://example.com/item', $data);
$client->put('https://example.com/item', $data);
$client->patch('https://example.com/item', $data);
$client->delete('https://example.com/item');
```

One-time headers and other request methods can be submitted using the `fetch()` method.

```
use Dormilich\HttpClient\Client;
use Dormilich\HttpClient\Transformer\UrlEncoder;

$client = new Client($httpClient, $requestFactory, $streamFactory);
$client->addTransformer(new UrlEncoder());

$search['foo'] = 'bar';
$header['authorization'] = 'Bearer 279ca9e0-ce59-48b2-8b6d-c0a6822195a1';
$result = $client->fetch('get', 'https://example.com/item', $search, $header);
```

Note: For requests that do not have a request body (GET, HEAD) the data will be put into the query string. As there is no formal definition of the structure of the query string, the format of the applied data encoder is used.

Data transformers
-----------------

[](#data-transformers)

Data transformers allow arbitrary data to be converted into a PSR-7 request and a PSR-7 response back into a specific data structure. For this purpose, several data transformers are predefined.

Data transformers implementing `TransformerInterface` can encode the request and decode the response.

```
use Dormilich\HttpClient\Client;
use Dormilich\HttpClient\Transformer\DomTransformer;
use Dormilich\HttpClient\Transformer\TextTransformer;
use Dormilich\HttpClient\Transformer\XmlTransformer;

$client = new Client($httpClient, $requestFactory, $streamFactory);
# converts DOMDocument
$client->addTransformer(new DomTransformer());
# converts data that can be cast to string
$client->addTransformer(new TextTransformer());
# converts SimpleXML objects
$client->addTransformer(new XmlTransformer());

$result = $client->post('https://example.com/item', $data);
```

Data transformers implementing `DataEncoderInterface` can encode the request but ignore the response.

```
use Dormilich\HttpClient\Client;
use Dormilich\HttpClient\Transformer\JsonEncoder;
use Dormilich\HttpClient\Transformer\UrlEncoder;

$client = new Client($httpClient, $requestFactory, $streamFactory);
# converts JsonSerializable & plain objects
$client->addTransformer(new JsonEncoder());
# converts arrays
$client->addTransformer(new UrlEncoder());

$result = $client->post('https://example.com/item', $data);
```

Data transformers implementing `DataDecoderInterface` can decode the response but ignore the request. These transformers are set up to only decode successful responses.

```
use Dormilich\HttpClient\Client;
use Dormilich\HttpClient\Transformer\JsonDecoder;
use Dormilich\HttpClient\Transformer\UrlDecoder;

$client = new Client($httpClient, $requestFactory, $streamFactory);
$client->addTransformer(new JsonDecoder(JSON_OBJECT_AS_ARRAY));
$client->addTransformer(new UrlDecoder());

$result = $client->post('https://example.com/item', $data);
```

If you need to decode an error response, you can wrap the transformer into a `Decoder` object and add the status restriction using a status matcher instance.

```
use Dormilich\HttpClient\Client;
use Dormilich\HttpClient\Decoder\Decoder;
use Dormilich\HttpClient\Transformer\JsonDecoder;
use Dormilich\HttpClient\Utility\StatusMatcher;

$decoder = new Decoder(new JsonDecoder());
$decoder->setStatusMatcher(StatusMatcher::clientError());

$client = new Client($httpClient, $requestFactory, $streamFactory);
// only decodes HTTP 4xx errors in JSON format
$client->addDecoder($decoder);
```

Should multiple data transformers encode the same data type or process the same response type, the first one defined wins.

The transformers for handling JSON and URL-encoded data have been split into encoders and decoders to allow the response to be decoded independently of the request encoder (e.g. when you want to decode a JSON response into a specific object).

### JSON transformers

[](#json-transformers)

The `JsonDecoder` and `JsonEncoder` accept any `JSON_*` constants for encoding and decoding as constructor argument.

```
use Dormilich\HttpClient\Transformer\JsonEncoder;

$default = new JsonEncoder();
$slashes = new JsonEncoder(JSON_UNESCAPED_SLASHES);

$data = 'text/plain';
$result = $default->encode($data);  // "text\/plain"
$result = $slashes->encode($data);  // "text/plain"
```

```
use Dormilich\HttpClient\Transformer\JsonDecoder;

$object = new JsonDecoder();
$array = new JsonDecoder(JSON_OBJECT_AS_ARRAY);

$json = '{"foo":"bar"}';
$result = $object->decode($json);   // $result->foo = 'bar';
$result = $array->decode($json);    // $result['foo'] = 'bar';
```

Note: Be aware that `JSON_NUMERIC_CHECK` will decode any integer string above `PHP_INT_MAX` into a floating point number. It will also convert numeric strings that may not be intended for conversion (e.g. phone numbers, postal codes, etc.).

### URL transformers

[](#url-transformers)

These transformers url-encode/url-decode data. By default, this uses the PHP-style of parsing. There is another parser available that strictly parses key-value pairs (i.e. no nested arrays).

```
use Dormilich\HttpClient\Transformer\UrlDecoder;
use Dormilich\HttpClient\Transformer\UrlEncoder;
use Dormilich\HttpClient\Utility\NvpQuery;

$php_encoder = new UrlEncoder();
$nvp_encoder = new UrlEncoder(new NvpQuery());

$data['q'][] = 'foo';
$data['q'][] = 'bar';

$query_php = $php_encoder->encode($data);   // "q%5B0%5D=foo&q%5B1%5D=bar"
$query_nvp = $nvp_encoder->encode($data);   // "q=foo&q=bar"

$php_decoder = new UrlEncoder();
$nvp_decoder = new UrlEncoder(new NvpQuery());

$result = $php_decoder->decode($query_php)  // ['q' => ['foo', 'bar']]
$result = $php_decoder->decode($query_nvp)  // ['q' => 'bar']
$result = $nvp_decoder->decode($query_nvp)  // ['q' => ['foo', 'bar']]
$result = $nvp_decoder->decode($query_php)  // ['q[0]' => 'foo', 'q[1]' => 'bar']
```

Request modification
--------------------

[](#request-modification)

Despite encoding data for the request, encoders can also be used for modifying the request. Therefore, the encoder must support `Psr\Http\Message\RequestInterface` as payload data type in the encoder's `supports()` method.

An example where this is useful are encoders that modify the request, e.g. adding headers.

```
use Dormilich\HttpClient\Client;
use Dormilich\HttpClient\Encoder\Header\ContentLength;

$client = new Client($httpClient, $requestFactory, $streamFactory);
// this will add the `Content-Length` header, if appropriate
$client->addEncoder(new ContentLength());
```

Parsing the response
--------------------

[](#parsing-the-response)

The response can be processed by defining response decoders or data decoders. Data decoders will only be used on successful responses while response decoders can be configured to process any (specific) response.

In contrast to encoders, the client does not need to have decoders defined, it will return the response body content if no decoder matches (or exists).

```
use Psr\Log\LoggerInterface;
use Dormilich\HttpClient\Client;
use Dormilich\HttpClient\Decoder\ErrorDecoder;
use Dormilich\HttpClient\Exception\RequestException;
use Dormilich\HttpClient\Transformer\JsonDecoder;

try {
    $client = new Client($httpClient, $requestFactory, $streamFactory);
    // converts a failed request into an exception
    // using the request body as exception message
    $client->addDecoder(new ErrorDecoder());
    $client->addTransformer(new JsonDecoder());
    $result = $client->get('https://example.com/toc')
} catch (RequestException $e) {
    $context['request'] = $e->getRequest();
    $context['response'] = $e->getResponse();
    $logger->error($e->getMessage(), $context);
}
```

Exceptions
----------

[](#exceptions)

Beside the aforementioned `UnsupportedDataTypeException` that indicates a setup issue, the client can also throw a `RequestException`. The PSR-18 exceptions are wrapped into a `RequestException`and failures to encode or decode will throw an `EncoderException` or `DecoderException`, respectively.

###  Health Score

33

—

LowBetter than 75% of packages

Maintenance60

Regular maintenance activity

Popularity9

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~738 days

Total

3

Last Release

253d ago

PHP version history (2 changes)7.4.x-devPHP &gt;=7.4

0.1.0PHP ^8.0

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/392135?v=4)[Bertold von Dormilich](/maintainers/Dormilich)[@Dormilich](https://github.com/Dormilich)

---

Top Contributors

[![Dormilich](https://avatars.githubusercontent.com/u/392135?v=4)](https://github.com/Dormilich "Dormilich (35 commits)")

---

Tags

composer

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/dormilich-http-client/health.svg)

```
[![Health](https://phpackages.com/badges/dormilich-http-client/health.svg)](https://phpackages.com/packages/dormilich-http-client)
```

###  Alternatives

[guzzlehttp/psr7

PSR-7 message implementation that also provides common utility methods

8.0k1.0B3.1k](/packages/guzzlehttp-psr7)[league/uri

URI manipulation library

1.1k206.4M276](/packages/league-uri)[php-http/client-common

Common HTTP Client implementations and tools for HTTPlug

1.0k225.5M571](/packages/php-http-client-common)[laudis/neo4j-php-client

Neo4j-PHP-Client is the most advanced PHP Client for Neo4j

184616.9k31](/packages/laudis-neo4j-php-client)[elastic/transport

HTTP transport PHP library for Elastic products

1920.6M7](/packages/elastic-transport)[phpro/http-tools

HTTP tools for developing more consistent HTTP implementations.

28137.8k](/packages/phpro-http-tools)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
