PHPackages                             four-bytes/four-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. four-bytes/four-http-client

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

four-bytes/four-http-client
===========================

Modern PHP 8.4+ HTTP client factory and middleware library for API integrations

4.0.1(2mo ago)09MITPHPPHP &gt;=8.4

Since Aug 25Pushed 1mo agoCompare

[ Source](https://github.com/four-bytes/four-http-client)[ Packagist](https://packagist.org/packages/four-bytes/four-http-client)[ RSS](/packages/four-bytes-four-http-client/feed)WikiDiscussions master Synced 1mo ago

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

Four HTTP Client
================

[](#four-http-client)

A modern PSR-18 HTTP client library for PHP 8.4+ with middleware support. Built for API integrations with generic transport and authentication layers.

Features
--------

[](#features)

- **PSR-18 Compliant** — Works with any PSR-18 compatible client
- **Middleware Stack** — Logging, rate limiting, retry, authentication
- **Authentication** — Bearer tokens, API keys, OAuth 2.0, OAuth 1.0a
- **Retry Logic** — Exponential backoff with configurable policies
- **Error Mapping** — 401 → AuthenticationException, 404 → NotFoundException, 429 → RateLimitException

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

[](#installation)

```
composer require four-bytes/four-http-client
```

Requires PHP 8.4+ and PSR packages:

- `psr/http-client: ^1.0`
- `psr/http-factory: ^1.0`
- `psr/http-message: ^2.0`
- `psr/log: ^3.0`

Recommended: `php-http/discovery` for automatic transport discovery.

Quick Start
-----------

[](#quick-start)

### Option 1: PSR-18 Client with HttpClientFactory

[](#option-1-psr-18-client-with-httpclientfactory)

Build a PSR-18 compliant client and use it directly with PSR-17 request factories:

```
use Four\Http\Configuration\ClientConfig;
use Four\Http\Factory\HttpClientFactory;
use Nyholm\Psr7\Factory\Psr17Factory;

// Build a PSR-18 client with middleware stack
$factory = new HttpClientFactory();

$config = ClientConfig::create('https://api.example.com')
    ->withAuth('bearer', 'your-token')
    ->withTimeout(30.0)
    ->build();

$psrClient = $factory->create($config);

// Use PSR-17 request factory to build requests
$requestFactory = new Psr17Factory();
$request = $requestFactory->createRequest('GET', 'https://api.example.com/data');

$response = $psrClient->sendRequest($request);
$data = json_decode((string) $response->getBody(), true);
```

### Option 2: Extend ApiClient for Custom API Clients

[](#option-2-extend-apiclient-for-custom-api-clients)

Create a typed client for your specific API:

```
use Four\Http\Client\ApiClient;
use Four\Http\Configuration\ClientConfig;
use Four\Http\Factory\ApiClientFactory;

class MyApiClient extends ApiClient
{
    public function getUser(int $id): array
    {
        return $this->httpGet('/users/' . $id);
    }

    public function createUser(array $data): array
    {
        return $this->httpPost('/users', $data);
    }

    public function updateUser(int $id, array $data): array
    {
        return $this->httpPatch('/users/' . $id, $data);
    }

    public function deleteUser(int $id): void
    {
        $this->httpDelete('/users/' . $id);
    }
}

$config = ClientConfig::create('https://api.example.com')
    ->withAuth('bearer', 'your-token')
    ->withTimeout(30.0)
    ->build();

$factory = new ApiClientFactory();
$client = $factory->create($config, MyApiClient::class);

$user = $client->getUser(42);
$newUser = $client->createUser(['name' => 'John']);
```

Configuration
-------------

[](#configuration)

### ClientConfigBuilder

[](#clientconfigbuilder)

Fluent builder for client configuration:

```
$config = ClientConfig::create('https://api.example.com')
    // Authentication (simple)
    ->withAuth('bearer', 'your-token')
    // or with AuthProvider
    ->withAuthentication($authProvider)

    // Headers
    ->withHeaders(['X-Custom-Header' => 'value'])
    ->withUserAgent('MyApp/1.0')
    ->withAccept('application/json')
    ->withContentType('application/json')

    // Timeouts
    ->withTimeout(30.0)
    ->withMaxRedirects(3)

    // Middleware (enabled via methods below)
    ->withLogging($logger)
    ->withRateLimit($rateLimiter)
    ->withRetries($retryConfig)

    ->build();
```

### Retry Configuration

[](#retry-configuration)

```
use Four\Http\Configuration\RetryConfig;

// Default: 3 attempts, exponential backoff
$config = RetryConfig::default();

// Conservative for rate-limited APIs
$config = RetryConfig::conservative();

// Aggressive for robust APIs
$config = RetryConfig::aggressive();

// Custom
$config = new RetryConfig(
    maxAttempts: 5,
    initialDelay: 1.0,
    multiplier: 2.0,
    maxDelay: 60.0,
    retryableStatusCodes: [429, 500, 502, 503, 504]
);

// Simple method on builder
$config = ClientConfig::create('https://api.example.com')
    ->withRetryPolicy(maxAttempts: 3, retryableStatusCodes: [429, 500, 502, 503, 504])
    ->build();
```

Middleware
----------

[](#middleware)

### Logging

[](#logging)

```
use Psr\Log\NullLogger;

$config = ClientConfig::create('https://api.example.com')
    ->withLogging(new NullLogger())
    // or with custom logger
    ->withLogging($myPsr3Logger)
    ->build();
```

### Rate Limiting

[](#rate-limiting)

Requires `four-bytes/four-rate-limiting`:

```
use Four\RateLimit\RateLimiterFactory;
use Four\RateLimit\RateLimitConfiguration;

$config = new RateLimitConfiguration(
    algorithm: RateLimitConfiguration::ALGORITHM_TOKEN_BUCKET,
    ratePerSecond: 10.0,
    burstCapacity: 20,
);

$rateLimiter = (new RateLimiterFactory())->create($config);

$clientConfig = ClientConfig::create('https://api.example.com')
    ->withRateLimit($rateLimiter)
    ->build();
```

### Retry

[](#retry)

```
$config = ClientConfig::create('https://api.example.com')
    ->withRetries(RetryConfig::default())
    ->build();
```

### Custom Middleware

[](#custom-middleware)

Implement `Four\Http\Middleware\MiddlewareInterface`:

```
use Four\Http\Middleware\MiddlewareInterface;
use Four\Http\Transport\HttpTransportInterface;

class CustomMiddleware implements MiddlewareInterface
{
    public function __construct(private LoggerInterface $logger) {}

    public function wrap(HttpTransportInterface $transport): HttpTransportInterface
    {
        return new CustomTransportWrapper($transport, $this->logger);
    }

    public function getName(): string
    {
        return 'custom';
    }

    public function getPriority(): int
    {
        return 100;
    }
}

$config = ClientConfig::create('https://api.example.com')
    ->withMiddleware(['logging', new CustomMiddleware($logger)])
    ->build();
```

Authentication
--------------

[](#authentication)

### TokenProvider

[](#tokenprovider)

Simple bearer/API tokens:

```
use Four\Http\Authentication\TokenProvider;

// Bearer token (default)
$provider = TokenProvider::bearer('your-access-token');

// API key with custom header
$provider = TokenProvider::apiKey('your-api-key', 'X-API-Key');

// Custom header/prefix
$provider = new TokenProvider('your-token', 'X-Custom-Auth', 'Token');

$config = ClientConfig::create('https://api.example.com')
    ->withAuthentication($provider)
    ->build();
```

### OAuthProvider

[](#oauthprovider)

OAuth 2.0 with automatic token refresh:

```
use Four\Http\Authentication\OAuthProvider;

// OAuth 2.0 with client credentials or refresh token flow
$auth = new OAuthProvider(
    clientId: 'your-client-id',
    clientSecret: 'your-client-secret',
    tokenEndpoint: 'https://api.example.com/oauth/token',
    httpClient: $psr18Client,
    requestFactory: $requestFactory,
    streamFactory: $streamFactory,
    refreshToken: 'your-refresh-token',   // optional
    scopes: ['read', 'write'],            // optional
);
```

### OAuth1aProvider

[](#oauth1aprovider)

OAuth 1.0a signature-based authentication:

```
use Four\Http\Authentication\OAuth1aProvider;

// OAuth 1.0a signature-based authentication
$auth = new OAuth1aProvider(
    consumerKey: 'your-consumer-key',
    consumerSecret: 'your-consumer-secret',
    accessToken: 'your-access-token',
    tokenSecret: 'your-token-secret',
);
```

Custom Transport
----------------

[](#custom-transport)

Implement `Four\Http\Transport\HttpTransportInterface` for custom HTTP backends:

```
use Four\Http\Transport\HttpTransportInterface;
use Four\Http\Transport\HttpResponseInterface;

class MyCustomTransport implements HttpTransportInterface
{
    public function request(
        string $method,
        string $url,
        array $headers = [],
        ?string $body = null
    ): HttpResponseInterface {
        // Your HTTP implementation
        return new MyCustomResponse($statusCode, $headers, $body);
    }
}

$transport = new MyCustomTransport();
$client = new TransportPsr18Adapter($transport);
```

Error Handling
--------------

[](#error-handling)

The library maps HTTP status codes to specific exceptions:

```
use Four\Http\Client\ApiClient;
use Four\Http\Exception\HttpClientException;
use Four\Http\Exception\AuthenticationException;
use Four\Http\Exception\NotFoundException;
use Four\Http\Exception\RateLimitException;
use Four\Http\Exception\RetryableException;

class MyApiClient extends ApiClient
{
    public function getData(): array
    {
        try {
            return $this->httpGet('/api/data');
        } catch (NotFoundException $e) {
            // 404 - Resource not found
            echo "Not found: " . $e->getMessage();
        } catch (AuthenticationException $e) {
            // 401/403 - Auth failed
            echo "Auth error: " . $e->getMessage();
        } catch (RateLimitException $e) {
            // 429 - Rate limited
            $retryAfter = $e->getRetryAfter();
            sleep($retryAfter);
        } catch (RetryableException $e) {
            // 500, 502, 503, 504 - Server errors, will be retried automatically
            echo "Server error: " . $e->getMessage();
        } catch (HttpClientException $e) {
            // Other HTTP errors
            echo "HTTP error: " . $e->getMessage();
        }

        return [];
    }
}
```

Requirements
------------

[](#requirements)

- **PHP 8.4+**
- **psr/http-client: ^1.0**
- **psr/http-factory: ^1.0**
- **psr/http-message: ^2.0**
- **psr/log: ^3.0**
- **php-http/discovery: ^1.19**

Optional:

- **symfony/http-client** — Alternative transport
- **guzzlehttp/guzzle** — Alternative transport

License
-------

[](#license)

MIT License - see [LICENSE](LICENSE) file.

###  Health Score

41

—

FairBetter than 89% of packages

Maintenance87

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity55

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 ~93 days

Total

3

Last Release

82d ago

Major Versions

v1.0.0 → 4.0.02026-02-26

### Community

Maintainers

![](https://www.gravatar.com/avatar/433108b332161ce972e4cab8308652a145ed1c3f132de17b04b21f524d4d2dae?d=identicon)[four-bytes-robby](/maintainers/four-bytes-robby)

---

Top Contributors

[![four-bytes-robby](https://avatars.githubusercontent.com/u/22675949?v=4)](https://github.com/four-bytes-robby "four-bytes-robby (18 commits)")

---

Tags

php-libraryhttppsr-7middlewareapiclientpsr-18rate limiting

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

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

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

###  Alternatives

[phpro/http-tools

HTTP tools for developing more consistent HTTP implementations.

28137.8k](/packages/phpro-http-tools)[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

2020.6M7](/packages/elastic-transport)[vultr/vultr-php

The Official Vultr API PHP Wrapper.

2243.9k1](/packages/vultr-vultr-php)[chillerlan/php-httpinterface

A PSR-7/17/18 http message/client implementation

1417.1k5](/packages/chillerlan-php-httpinterface)[zelenin/http-client

PSR-18 compatible HTTP client with middleware support

322.1k3](/packages/zelenin-http-client)

PHPackages © 2026

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