PHPackages                             villaflor/connection - 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. [API Development](/categories/api)
4. /
5. villaflor/connection

ActiveLibrary[API Development](/categories/api)

villaflor/connection
====================

Send requests to any API endpoint with ease.

5.0.0(6mo ago)15.0k↑28.6%[1 PRs](https://github.com/villaflor/connection/pulls)1MITPHPPHP ^8.3CI passing

Since Aug 16Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/villaflor/connection)[ Packagist](https://packagist.org/packages/villaflor/connection)[ Docs](https://github.com/villaflor/connection)[ GitHub Sponsors](https://github.com/villaflor)[ RSS](/packages/villaflor-connection/feed)WikiDiscussions main Synced 2d ago

READMEChangelog (10)Dependencies (5)Versions (16)Used By (1)

Connection - HTTP Client for PHP
================================

[](#connection---http-client-for-php)

[![Latest Version on Packagist](https://camo.githubusercontent.com/f551ed9dfdd101941d79a8c144e26853ff35b31f619329bd693b10b130aabc45/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f76696c6c61666c6f722f636f6e6e656374696f6e2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/villaflor/connection)[![PHP Version Supported](https://camo.githubusercontent.com/f448888fc138355a151e17ff5340af7f438fd82ed66007cffb8b345c50fb1805/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f76696c6c61666c6f722f636f6e6e656374696f6e3f7374796c653d666c61742d737175617265)](https://packagist.org/packages/villaflor/connection)[![License](https://camo.githubusercontent.com/59cb994eadeebf270f349d5e340267523534db5fb5dd4d44a303f3a0b96cb2c0/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f76696c6c61666c6f722f636f6e6e656374696f6e2e7376673f7374796c653d666c61742d737175617265)](https://github.com/villaflor/connection/blob/main/LICENSE)[![Total Downloads](https://camo.githubusercontent.com/6e9df4dda0d0db1f49cb43ee1bac25ef1f4586882d6dd620ff6292d72389fd3f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f76696c6c61666c6f722f636f6e6e656374696f6e2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/villaflor/connection)[![Tests](https://github.com/villaflor/connection/actions/workflows/run-tests.yml/badge.svg?branch=main)](https://github.com/villaflor/connection/actions/workflows/run-tests.yml)![100% Coverage](https://camo.githubusercontent.com/994d68acb2aadf1c3c7711ddcb3b30429246a6c05da9e601f62c3f932ac795a8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f7665726167652d3130302532352d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)

A lightweight, PSR-7 compliant HTTP client for PHP 8.3+ with no dependencies. Send requests to any API endpoint with ease using a clean, SOLID architecture.

Features
--------

[](#features)

### Core Features

[](#core-features)

✅ **Zero Dependencies** - Native cURL implementation, no Guzzle required ✅ **100% Test Coverage** - Fully tested and reliable ✅ **PSR-7 Compliant** - Standard HTTP message interfaces ✅ **Multiple Auth Methods** - API Token, API Key, Google Service Account, Custom Headers ✅ **SOLID Architecture** - Clean, maintainable, extensible code ✅ **Type Safe** - Full PHP 8.3+ type hints

### Advanced Features

[](#advanced-features)

✅ **Middleware Pipeline** - Extensible request/response processing ✅ **Retry Logic** - Automatic retry with exponential backoff ✅ **Rate Limiting** - Token bucket algorithm for API rate limits ✅ **Response Caching** - HTTP-aware caching with TTL support ✅ **Cookie Management** - Automatic cookie jar with session persistence ✅ **Event System** - Observable HTTP lifecycle events ✅ **File Uploads** - Multipart form data support ✅ **Proxy &amp; SSL** - Full proxy and SSL/TLS configuration ✅ **PSR-3 Logging** - Request/response logging support

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

[](#installation)

```
composer require villaflor/connection
```

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

[](#requirements)

- PHP 8.3 or higher
- ext-curl
- ext-json
- ext-openssl

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

[](#quick-start)

```
use Villaflor\Connection\Adapter\Curl;
use Villaflor\Connection\Auth\APIToken;

// Create a client with Bearer token authentication
$auth = new APIToken('your-api-token-here');
$client = new Curl($auth, 'https://api.example.com');

// Make a GET request
$response = $client->get('/users');
$data = json_decode($response->getBody());

// Make a POST request
$response = $client->post('/users', [
    'name' => 'John Doe',
    'email' => 'john@example.com',
]);
```

Authentication Methods
----------------------

[](#authentication-methods)

### API Token (Bearer)

[](#api-token-bearer)

```
use Villaflor\Connection\Auth\APIToken;

$auth = new APIToken('your-token');
// Sends: Authorization: Bearer your-token
```

### API Key

[](#api-key)

```
use Villaflor\Connection\Auth\APIKey;

$auth = new APIKey('your-api-key');
// Sends: X-API-Key: your-api-key
```

### Custom Headers

[](#custom-headers)

```
use Villaflor\Connection\Auth\CustomHeaders;

$auth = new CustomHeaders([
    'X-Custom-Auth' => 'custom-value',
    'X-Client-ID' => 'client-123',
]);
```

### User Service Key

[](#user-service-key)

```
use Villaflor\Connection\Auth\UserServiceKey;

$auth = new UserServiceKey('user-id', 'service-key');
// Sends: X-User-Id: user-id, X-Service-Key: service-key
```

### Google Service Account

[](#google-service-account)

```
use Villaflor\Connection\Auth\GoogleServiceAccount;

$auth = new GoogleServiceAccount(
    '/path/to/service-account.json',
    'https://www.googleapis.com/auth/cloud-platform'
);
// Generates and sends JWT token
```

### No Authentication

[](#no-authentication)

```
use Villaflor\Connection\Auth\None;

$auth = new None();
```

HTTP Methods
------------

[](#http-methods)

### GET Request

[](#get-request)

```
// Simple GET
$response = $client->get('/users');

// GET with query parameters
$response = $client->get('/users', ['page' => 1, 'limit' => 10]);

// GET with custom headers
$response = $client->get('/users', [], ['X-Custom' => 'value']);
```

### POST Request

[](#post-request)

```
// POST with JSON body
$response = $client->post('/users', [
    'name' => 'John Doe',
    'email' => 'john@example.com',
]);

// POST with form data
$response = $client->post('/users', [
    'form_params' => [
        'name' => 'John Doe',
        'email' => 'john@example.com',
    ],
]);
```

### PUT Request

[](#put-request)

```
$response = $client->put('/users/123', [
    'name' => 'Jane Doe',
    'email' => 'jane@example.com',
]);
```

### PATCH Request

[](#patch-request)

```
$response = $client->patch('/users/123', [
    'email' => 'newemail@example.com',
]);
```

### DELETE Request

[](#delete-request)

```
$response = $client->delete('/users/123');

// DELETE with body (if API requires it)
$response = $client->delete('/users/123', [
    'reason' => 'User requested deletion',
]);
```

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

[](#configuration)

### Timeouts

[](#timeouts)

```
$client = new Curl($auth, 'https://api.example.com');

// Set request timeout (default: 30 seconds)
$client->setTimeout(60);

// Set connection timeout (default: 10 seconds)
$client->setConnectTimeout(5);
```

### Using Relative URLs

[](#using-relative-urls)

```
// Base URI is set in constructor
$client = new Curl($auth, 'https://api.example.com');

// Use relative paths
$response = $client->get('/users'); // https://api.example.com/users
$response = $client->get('posts');  // https://api.example.com/posts

// Or use absolute URLs (ignores base URI)
$response = $client->get('https://other-api.com/data');
```

Working with Responses
----------------------

[](#working-with-responses)

All responses implement PSR-7 `ResponseInterface`:

```
$response = $client->get('/users');

// Get status code
$statusCode = $response->getStatusCode(); // 200

// Get reason phrase
$reason = $response->getReasonPhrase(); // "OK"

// Get headers
$headers = $response->getHeaders();
$contentType = $response->getHeaderLine('Content-Type');

// Get body
$body = (string) $response->getBody();
$data = json_decode($response->getBody());

// PSR-7 methods
$response = $response->withHeader('X-Custom', 'value'); // Immutable
$newResponse = $response->withStatus(404, 'Not Found');
```

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

[](#error-handling)

```
use Villaflor\Connection\Exception\ResponseException;
use Villaflor\Connection\Exception\JSONException;

try {
    $response = $client->get('/users/999');
} catch (ResponseException $e) {
    // HTTP 4xx or 5xx error
    echo "Error: " . $e->getMessage();
    echo "Status Code: " . $e->getCode();

    // Access previous exception if available
    if ($e->getPrevious() instanceof JSONException) {
        echo "JSON parsing failed";
    }
}
```

### Exception Types

[](#exception-types)

- `ResponseException` - Thrown for HTTP 4xx and 5xx errors, or cURL errors
- `JSONException` - Thrown when JSON response cannot be decoded
- `InvalidArgumentException` - Thrown for invalid method names or parameters

### Error Response Formats

[](#error-response-formats)

The library automatically parses various JSON error formats:

```
// Format 1: errors array
{"errors": [{"code": 1003, "message": "Invalid input"}]}

// Format 2: message field
{"message": "Resource not found"}

// Format 3: error field (string)
{"error": "Authentication failed"}

// Format 4: error field (object)
{"error": {"message": "Rate limit exceeded"}}
```

Advanced Usage
--------------

[](#advanced-usage)

### Custom Request Method

[](#custom-request-method)

```
$response = $client->request('GET', '/users', ['page' => 1], ['X-Custom' => 'value']);
```

### Working with Different Content Types

[](#working-with-different-content-types)

```
// JSON (default)
$response = $client->post('/api/data', ['key' => 'value']);
// Sends: Content-Type: application/json

// Form data
$response = $client->post('/api/form', [
    'form_params' => ['key' => 'value']
]);
// Sends: Content-Type: application/x-www-form-urlencoded
```

### Query Parameters with Existing Query String

[](#query-parameters-with-existing-query-string)

```
// Automatically handles existing query parameters
$response = $client->get('/search?q=test', ['page' => 2]);
// Requests: /search?q=test&page=2
```

Fluent API with ConnectionBuilder
---------------------------------

[](#fluent-api-with-connectionbuilder)

Build clients with a fluent, chainable API:

```
use Villaflor\Connection\ConnectionBuilder;

$client = ConnectionBuilder::create()
    ->withBaseUri('https://api.example.com')
    ->withBearerToken('your-token')
    ->withTimeout(60)
    ->withConnectTimeout(10)
    ->build();

// Make requests
$response = $client->get('/users');
```

Advanced Features
-----------------

[](#advanced-features-1)

### Retry Logic with Exponential Backoff

[](#retry-logic-with-exponential-backoff)

Automatically retry failed requests with configurable backoff:

```
use Villaflor\Connection\Retry\RetryConfig;

$client = new Curl($auth, 'https://api.example.com');

// Configure retry behavior
$retryConfig = new RetryConfig(
    maxAttempts: 3,                                      // Retry up to 3 times
    retryableStatusCodes: [408, 429, 500, 502, 503, 504], // Which status codes to retry
    exponentialBackoff: true,                            // Use exponential backoff
    baseDelay: 1000,                                     // Start with 1 second delay
    maxDelay: 30000                                      // Maximum 30 seconds delay
);

$client->setRetryConfig($retryConfig);

// Requests will automatically retry on failures
$response = $client->get('/unstable-endpoint');
```

Retry delays: 1s → 2s → 4s → 8s → ...

### Middleware Pipeline

[](#middleware-pipeline)

Extend functionality with custom middleware:

```
use Villaflor\Connection\Middleware\MiddlewareInterface;
use Psr\Http\Message\ResponseInterface;

class CustomMiddleware implements MiddlewareInterface
{
    public function handle(
        string $method,
        string $uri,
        array $data,
        array $headers,
        callable $next
    ): ResponseInterface {
        // Before request
        $headers['X-Custom-Header'] = 'value';

        // Execute request
        $response = $next($method, $uri, $data, $headers);

        // After response
        return $response;
    }
}

$client->addMiddleware(new CustomMiddleware);
```

### Rate Limiting

[](#rate-limiting)

Prevent exceeding API rate limits:

```
use Villaflor\Connection\RateLimit\RateLimiter;
use Villaflor\Connection\Middleware\RateLimitMiddleware;

$client = new Curl($auth, 'https://api.example.com');

// Limit to 100 requests per 60 seconds
$limiter = new RateLimiter(maxRequests: 100, perSeconds: 60);
$client->addMiddleware(new RateLimitMiddleware($limiter));

// Requests will automatically throttle
for ($i = 0; $i < 200; $i++) {
    $client->get('/data'); // Will throttle after 100 requests
}
```

### Response Caching

[](#response-caching)

Cache responses to improve performance:

```
use Villaflor\Connection\Cache\ArrayCache;
use Villaflor\Connection\Middleware\CachingMiddleware;

$client = new Curl($auth, 'https://api.example.com');

$cache = new ArrayCache;
$cachingMiddleware = new CachingMiddleware(
    cache: $cache,
    defaultTtl: 300,  // 5 minutes
    cacheableMethods: ['GET']
);

$client->addMiddleware($cachingMiddleware);

// First request hits the API
$response1 = $client->get('/data'); // ~200ms

// Second request uses cache
$response2 = $client->get('/data'); // addMiddleware(new CookieMiddleware($jar));

// Login request sets cookies
$client->post('/login', ['username' => 'user', 'password' => 'pass']);

// Subsequent requests automatically include cookies
$client->get('/dashboard'); // Cookie sent automatically
$client->get('/profile');   // Cookie sent automatically
```

### Event System

[](#event-system)

Monitor and observe HTTP lifecycle:

```
use Villaflor\Connection\Events\EventDispatcher;
use Villaflor\Connection\Middleware\EventMiddleware;

$dispatcher = new EventDispatcher;

// Listen for events
$dispatcher->listen('request.sending', function ($event) {
    echo "Sending: {$event->method} {$event->uri}\n";
});

$dispatcher->listen('response.received', function ($event) {
    echo "Received: {$event->response->getStatusCode()} in {$event->duration}s\n";
});

$dispatcher->listen('request.failed', function ($event) {
    echo "Failed: {$event->exception->getMessage()}\n";
});

$client->addMiddleware(new EventMiddleware($dispatcher));
```

### Request/Response Logging

[](#requestresponse-logging)

PSR-3 compatible logging:

```
use Villaflor\Connection\Middleware\LoggingMiddleware;
use Psr\Log\LogLevel;

$client = new Curl($auth, 'https://api.example.com');

$client->addMiddleware(new LoggingMiddleware(
    logger: $logger,           // Any PSR-3 logger
    requestLevel: LogLevel::INFO,
    responseLevel: LogLevel::INFO,
    errorLevel: LogLevel::ERROR
));

// All requests/responses are logged
$client->get('/data');
```

### File Uploads

[](#file-uploads)

Upload files with multipart/form-data:

```
// Upload from file path
$client->post('/upload', [
    'description' => 'My file',
    'file' => '/path/to/file.pdf',
]);

// Upload raw content
$client->post('/upload', [
    'file' => [
        'name' => 'document.pdf',
        'contents' => $fileContent,
        'mime_type' => 'application/pdf',
    ],
]);

// Multiple files
$client->post('/upload', [
    'file1' => '/path/to/file1.pdf',
    'file2' => '/path/to/file2.jpg',
]);
```

### Proxy Configuration

[](#proxy-configuration)

Route requests through a proxy:

```
$client = new Curl($auth, 'https://api.example.com');

// Basic proxy
$client->setProxy('proxy.example.com:8080');

// Proxy with authentication
$client->setProxy('proxy.example.com:8080', 'username:password');

// With ConnectionBuilder
$client = ConnectionBuilder::create()
    ->withBaseUri('https://api.example.com')
    ->withProxy('proxy.example.com:8080', 'user:pass')
    ->build();
```

### SSL/TLS Configuration

[](#ssltls-configuration)

Configure SSL verification and certificates:

```
$client = new Curl($auth, 'https://api.example.com');

// Enable/disable SSL verification
$client->setVerifyPeer(true);  // Verify SSL certificate
$client->setVerifyHost(true);  // Verify hostname

// Custom CA bundle
$client->setCaBundle('/path/to/ca-bundle.crt');

// Client certificates (mutual TLS)
$client->setSslCert('/path/to/cert.pem', '/path/to/key.pem');

// With ConnectionBuilder
$client = ConnectionBuilder::create()
    ->withBaseUri('https://api.example.com')
    ->withVerifyPeer(true)
    ->withCaBundle('/path/to/ca-bundle.crt')
    ->build();
```

Examples
--------

[](#examples)

Comprehensive examples are available in the [`examples/`](examples/) directory:

1. **01-basic-usage.php** - HTTP methods and basic operations
2. **02-authentication.php** - All authentication strategies
3. **03-retry-logic.php** - Retry configuration patterns
4. **04-middleware.php** - Middleware system
5. **05-file-uploads.php** - File upload examples
6. **06-events.php** - Event system usage
7. **07-proxy-ssl.php** - Proxy and SSL configuration
8. **08-advanced-patterns.php** - Production patterns
9. **09-caching.php** - Response caching
10. **10-cookies.php** - Cookie management

See [`examples/README.md`](examples/README.md) for a complete guide.

Migration from Guzzle
---------------------

[](#migration-from-guzzle)

If you're migrating from the previous Guzzle-based version:

**Before (v4.x with Guzzle):**

```
use Villaflor\Connection\Adapter\Guzzle;

$client = new Guzzle($auth, 'https://api.example.com');
```

**After (v5.x with Curl):**

```
use Villaflor\Connection\Adapter\Curl;

$client = new Curl($auth, 'https://api.example.com');
```

The API is identical - just change the class name! All methods, parameters, and return types remain the same.

Architecture
------------

[](#architecture)

This package follows SOLID principles with a clean architecture:

- **Adapter Pattern**: Easily swap HTTP clients (currently Curl, previously Guzzle)
- **Strategy Pattern**: Multiple authentication strategies
- **Dependency Inversion**: Depend on interfaces, not concrete implementations
- **PSR-7 Compliance**: Standard HTTP message interfaces

### Interface Hierarchy

[](#interface-hierarchy)

```
AdapterInterface
├── Curl (Native PHP cURL implementation)

AuthInterface
├── APIToken
├── APIKey
├── CustomHeaders
├── UserServiceKey
├── GoogleServiceAccount
└── None

ResponseInterface (PSR-7)
└── Response

StreamInterface (PSR-7)
└── Stream

```

Testing
-------

[](#testing)

```
# Run tests
composer test

# Run tests with coverage
composer test-coverage

# Run code formatting
composer format
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for recent changes.

Contributing
------------

[](#contributing)

Contributions are welcome! Please feel free to submit a Pull Request.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [Mark Anthony Villaflor](https://github.com/villaflor)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

51

—

FairBetter than 95% of packages

Maintenance77

Regular maintenance activity

Popularity25

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity74

Established project with proven stability

 Bus Factor1

Top contributor holds 54% 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 ~144 days

Recently: every ~277 days

Total

12

Last Release

198d ago

Major Versions

1.2.1 → 2.0.02022-12-07

2.1.0 → v3.0.02023-09-25

v3.0.0 → 4.0.02025-09-03

4.0.0 → 5.0.02025-12-17

PHP version history (4 changes)1.0.0PHP ^7.4|^8.0

2.0.0PHP ^8.0|^8.1

v3.0.0PHP ^8.1|^8.2

4.0.0PHP ^8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/60b659450734f21a7a920500011a61a9996cb5112cf18a05bf8131916167e50a?d=identicon)[villaflor](/maintainers/villaflor)

---

Top Contributors

[![villaflor](https://avatars.githubusercontent.com/u/15763160?v=4)](https://github.com/villaflor "villaflor (34 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (18 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (11 commits)")

---

Tags

Connectionvillaflor

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/villaflor-connection/health.svg)

```
[![Health](https://phpackages.com/badges/villaflor-connection/health.svg)](https://phpackages.com/packages/villaflor-connection)
```

###  Alternatives

[symfony/symfony

The Symfony PHP framework

31.4k87.2M2.2k](/packages/symfony-symfony)[algolia/algoliasearch-client-php

API powering the features of Algolia.

69735.1M159](/packages/algolia-algoliasearch-client-php)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.9M738](/packages/sylius-sylius)[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k15](/packages/tempest-framework)[flow-php/flow

PHP ETL - Extract Transform Load - Data processing framework

85036.3k](/packages/flow-php-flow)[telnyx/telnyx-php

Official Telnyx PHP SDK — APIs for Voice, SMS, MMS, WhatsApp, Fax, SIP Trunking, Wireless IoT, Call Control, and more. Build global communications on Telnyx's private carrier-grade network.

35789.4k2](/packages/telnyx-telnyx-php)

PHPackages © 2026

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