PHPackages                             elliephp/httpclient - 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. elliephp/httpclient

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

elliephp/httpclient
===================

A simple laravel inspired abstraction on top of Symfony HttpClient.

1.0.8(3mo ago)1581MITPHPPHP ^8.4

Since Nov 20Pushed 2mo agoCompare

[ Source](https://github.com/ElliePHP/HttpClient)[ Packagist](https://packagist.org/packages/elliephp/httpclient)[ Docs](https://github.com/elliephp/httpclient)[ RSS](/packages/elliephp-httpclient/feed)WikiDiscussions main Synced 1mo ago

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

ElliePHP HttpClient
===================

[](#elliephp-httpclient)

A simple, Laravel-inspired HTTP client abstraction built on top of Symfony HttpClient. This library provides a fluent, developer-friendly interface for making HTTP requests in PHP applications.

Features
--------

[](#features)

- Simple and intuitive API with fluent interface for building requests
- Static and instance methods available, use whichever style fits your needs
- Built-in authentication support for Bearer tokens and Basic auth
- Automatic JSON encoding and decoding with convenience methods
- Configurable retry strategies with exponential backoff
- Easy timeout control for requests
- Graceful error handling with custom exceptions
- Convenient response helper methods for checking status and accessing data

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

[](#installation)

Install via Composer:

```
composer require elliephp/httpclient
```

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

[](#requirements)

- PHP 8.4 or higher
- Symfony HttpClient component

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

[](#quick-start)

### Http Facade (Recommended)

[](#http-facade-recommended)

The `Http` facade provides a clean, static interface for making requests:

```
use ElliePHP\Components\HttpClient\Http;

// Simple GET request
$response = Http::get('https://api.example.com/users');

// Configured request with method chaining
$response = Http::withBaseUrl('https://api.example.com')
    ->withToken('your-api-token')
    ->withUserAgent('MyApp/1.0')
    ->acceptJson()
    ->get('/users');

// POST request
$response = Http::post('https://api.example.com/users', [
    'name' => 'John Doe',
    'email' => 'john@example.com'
]);

// Check response
if ($response->successful()) {
    $data = $response->json();
    echo "User created: " . $data['name'];
}
```

### Static Methods (HttpClient)

[](#static-methods-httpclient)

For quick, one-off requests, use static methods on `HttpClient`. Note that static methods do not support configuration chaining. They expect full, absolute URLs.

```
use ElliePHP\Components\HttpClient\HttpClient;

// GET request
$response = HttpClient::get('https://api.example.com/users');

// POST request
$response = HttpClient::post('https://api.example.com/users', [
    'name' => 'John Doe',
    'email' => 'john@example.com'
]);

// Check response
if ($response->successful()) {
    $data = $response->json();
    echo "User created: " . $data['name'];
}
```

### Instance Methods (Configured Usage)

[](#instance-methods-configured-usage)

For multiple requests with shared configuration, create an instance. When you use configuration methods like `withBaseUrl()`, `withToken()`, etc., they return a `ClientBuilder` instance that properly handles the configuration. The `ClientBuilder` has all the same request methods (get, post, put, patch, delete) and will use your configured settings.

```
$client = new HttpClient();

// This returns a ClientBuilder with your configuration applied
$response = $client
    ->withBaseUrl('https://api.example.com')
    ->withToken('your-api-token')
    ->acceptJson()
    ->get('/users');  // The ClientBuilder's get() method uses the base URL
```

**Important:** If you call request methods directly on the `HttpClient` instance without any configuration chaining, you must provide full URLs because the configuration is not stored on the `HttpClient` instance itself:

```
$client = new HttpClient();

// This will NOT work as expected because get() is called directly on HttpClient
// and HttpClient doesn't store the baseUrl configuration
$client->withBaseUrl('https://api.example.com');
$response = $client->get('/users');  // Error: /users is not a valid URL

// This works because the configuration returns ClientBuilder which handles it properly
$response = $client->withBaseUrl('https://api.example.com')->get('/users');
```

Usage Examples
--------------

[](#usage-examples)

### Making Requests

[](#making-requests)

#### GET Request

[](#get-request)

```
use ElliePHP\Components\HttpClient\Http;

// Simple GET
$response = Http::get('https://api.example.com/users');

// GET with query parameters
$response = Http::get('https://api.example.com/users', [
    'page' => 1,
    'limit' => 10
]);
```

#### POST Request

[](#post-request)

```
use ElliePHP\Components\HttpClient\Http;

// POST with form data
$response = Http::post('https://api.example.com/users', [
    'name' => 'John Doe',
    'email' => 'john@example.com'
]);

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

#### PUT Request

[](#put-request)

```
use ElliePHP\Components\HttpClient\Http;

$response = Http::put('https://api.example.com/users/123', [
    'name' => 'Jane Doe'
]);
```

#### PATCH Request

[](#patch-request)

```
use ElliePHP\Components\HttpClient\Http;

$response = Http::patch('https://api.example.com/users/123', [
    'status' => 'active'
]);
```

#### DELETE Request

[](#delete-request)

```
use ElliePHP\Components\HttpClient\Http;

$response = Http::delete('https://api.example.com/users/123');
```

#### File Uploads

[](#file-uploads)

The HTTP client supports file uploads using the `attach()` method. Files are automatically sent as `multipart/form-data`.

**Upload a single file:**

```
use ElliePHP\Components\HttpClient\Http;

// Upload a file by path
$response = Http::attach('file', '/path/to/image.jpg')
    ->post('https://api.example.com/upload');

// Upload with additional form data
$response = Http::attach('file', '/path/to/image.jpg')
    ->post('https://api.example.com/upload', [
        'description' => 'My uploaded image',
        'category' => 'photos'
    ]);
```

**Upload multiple files:**

```
// Attach multiple files
$response = Http::attach('avatar', '/path/to/avatar.jpg')
    ->attach('document', '/path/to/document.pdf')
    ->post('https://api.example.com/upload', [
        'user_id' => 123
    ]);
```

**Upload using file resource:**

```
// Open file and upload
$file = fopen('/path/to/file.jpg', 'r');
$response = Http::attach('file', $file)
    ->post('https://api.example.com/upload');

// Don't forget to close the file if you opened it manually
fclose($file);
```

**Upload with file resource in data array:**

```
// You can also pass file resources directly in the data array
$response = Http::post('https://api.example.com/upload', [
    'name' => 'John',
    'file' => fopen('/path/to/file.jpg', 'r')
]);
```

**Upload with authentication and configuration:**

```
$response = Http::withBaseUrl('https://api.example.com')
    ->withToken('your-api-token')
    ->withUserAgent('MyApp/1.0')
    ->attach('file', '/path/to/file.jpg')
    ->post('/upload', [
        'description' => 'Uploaded file'
    ]);
```

**Error Handling:**

The `attach()` method will throw an `InvalidArgumentException` if the file path doesn't exist, the file is not readable, or the provided value is not a file path or resource.

```
use ElliePHP\Components\HttpClient\Http;
use InvalidArgumentException;

try {
    $response = Http::attach('file', '/nonexistent/file.jpg')
        ->post('https://api.example.com/upload');
} catch (InvalidArgumentException $e) {
    echo "File error: " . $e->getMessage();
}
```

Note that file uploads work with POST, PUT, and PATCH requests. When files are attached, the request is automatically sent as `multipart/form-data`, even if `asJson()` was called earlier.

### Authentication

[](#authentication)

#### Bearer Token Authentication

[](#bearer-token-authentication)

```
use ElliePHP\Components\HttpClient\Http;

$response = Http::withToken('your-api-token')
    ->get('https://api.example.com/protected-resource');
```

#### Basic Authentication

[](#basic-authentication)

```
use ElliePHP\Components\HttpClient\Http;

$response = Http::withBasicAuth('username', 'password')
    ->get('https://api.example.com/protected-resource');
```

### Working with JSON

[](#working-with-json)

#### Sending JSON Requests

[](#sending-json-requests)

```
use ElliePHP\Components\HttpClient\Http;

// asJson() sets Content-Type header and encodes body as JSON
$response = Http::asJson()
    ->post('https://api.example.com/users', [
        'name' => 'John Doe',
        'email' => 'john@example.com',
        'metadata' => [
            'role' => 'admin',
            'department' => 'IT'
        ]
    ]);
```

#### Receiving JSON Responses

[](#receiving-json-responses)

```
use ElliePHP\Components\HttpClient\Http;

$response = Http::get('https://api.example.com/users/123');

// Get entire JSON response as array
$data = $response->json();
echo $data['name']; // John Doe

// Get specific key from JSON
$name = $response->json('name');
echo $name; // John Doe

// Handle invalid JSON gracefully
$data = $response->json(); // Returns null if JSON is invalid
```

#### Accept JSON Header

[](#accept-json-header)

```
use ElliePHP\Components\HttpClient\Http;

// Sets Accept: application/json header
$response = Http::acceptJson()
    ->get('https://api.example.com/users');
```

### Configuration Options

[](#configuration-options)

#### Base URL

[](#base-url)

```
use ElliePHP\Components\HttpClient\Http;

// Set base URL for all requests
$response = Http::withBaseUrl('https://api.example.com')
    ->get('/users'); // Requests https://api.example.com/users

// Absolute URLs override base URL
$response = Http::withBaseUrl('https://api.example.com')
    ->get('https://other-api.com/data'); // Requests https://other-api.com/data
```

#### Custom Headers

[](#custom-headers)

```
$client = new HttpClient();

// Add multiple headers
$response = $client
    ->withHeaders([
        'X-API-Key' => 'secret-key',
        'User-Agent' => 'MyApp/1.0',
        'X-Custom-Header' => 'value'
    ])
    ->get('https://api.example.com/data');

// Or use convenience methods for common headers
$response = Http::withUserAgent('MyApp/1.0')
    ->withHeader('X-API-Key', 'secret-key')
    ->get('https://api.example.com/data');
```

#### User-Agent Header

[](#user-agent-header)

```
// Set User-Agent header
$response = Http::withUserAgent('MyApp/1.0')
    ->get('https://api.example.com/data');
```

#### Content-Type Header

[](#content-type-header)

```
// Set Content-Type header
$response = Http::withContentType('application/xml')
    ->post('https://api.example.com/data', $xmlData);
```

#### Accept Header

[](#accept-header)

```
// Set Accept header
$response = Http::withAccept('application/xml')
    ->get('https://api.example.com/data');
```

#### Single Header

[](#single-header)

```
// Set a single custom header
$response = Http::withHeader('X-Custom-Header', 'value')
    ->get('https://api.example.com/data');
```

#### Maximum Redirects

[](#maximum-redirects)

```
// Configure maximum number of redirects to follow
$response = Http::withMaxRedirects(5)
    ->get('https://api.example.com/data');
```

#### SSL Verification

[](#ssl-verification)

```
// Disable SSL certificate verification (not recommended for production)
$response = Http::withVerify(false)
    ->get('https://self-signed-cert.example.com');

// Enable SSL verification (default)
$response = Http::withVerify(true)
    ->get('https://api.example.com/data');
```

#### Proxy Configuration

[](#proxy-configuration)

```
// Configure proxy for requests
$response = Http::withProxy('http://proxy.example.com:8080')
    ->get('https://api.example.com/data');
```

#### Timeout

[](#timeout)

```
use ElliePHP\Components\HttpClient\Http;

// Set timeout in seconds
$response = Http::withTimeout(30)
    ->get('https://api.example.com/slow-endpoint');
```

### Retry Configuration

[](#retry-configuration)

Configure automatic retry behavior for failed requests.

#### Exponential Backoff

[](#exponential-backoff)

```
use ElliePHP\Components\HttpClient\Http;

$response = Http::withRetry([
    'max_retries' => 3,      // Retry up to 3 times
    'delay' => 1000,         // Start with 1 second delay (milliseconds)
    'multiplier' => 2,       // Double delay each time: 1s, 2s, 4s
    'max_delay' => 10000,    // Cap delay at 10 seconds
])
    ->get('https://api.example.com/data');
```

#### Fixed Delay

[](#fixed-delay)

```
use ElliePHP\Components\HttpClient\Http;

$response = Http::withRetry([
    'max_retries' => 5,
    'delay' => 2000,         // 2 second delay
    'multiplier' => 1,       // Keep delay constant
])
    ->get('https://api.example.com/data');
```

#### Retry with Jitter

[](#retry-with-jitter)

Add randomness to prevent thundering herd problems:

```
use ElliePHP\Components\HttpClient\Http;

$response = Http::withRetry([
    'max_retries' => 3,
    'delay' => 1000,
    'multiplier' => 2,
    'jitter' => 0.1,         // Add ±10% random variation
])
    ->get('https://api.example.com/data');
```

#### Retry Specific Status Codes

[](#retry-specific-status-codes)

```
use ElliePHP\Components\HttpClient\Http;

$response = Http::withRetry([
    'max_retries' => 3,
    'delay' => 1000,
    'multiplier' => 2,
    'http_codes' => [429, 500, 502, 503, 504], // Only retry these codes
])
    ->get('https://api.example.com/data');
```

### Advanced Configuration

[](#advanced-configuration)

#### Symfony HttpClient Options

[](#symfony-httpclient-options)

Pass any Symfony HttpClient options directly:

```
use ElliePHP\Components\HttpClient\Http;

$response = Http::withOptions([
    'max_redirects' => 5,
    'timeout' => 30,
    'verify_peer' => true,
    'verify_host' => true,
])
    ->get('https://api.example.com/data');
```

For all available options, see the [Symfony HttpClient documentation](https://symfony.com/doc/current/http_client.html#configuration).

### Response Handling

[](#response-handling)

#### Check Response Status

[](#check-response-status)

The Response class provides many convenience methods for checking HTTP status codes.

**General Status Checks:**

```
use ElliePHP\Components\HttpClient\Http;

$response = Http::get('https://api.example.com/users');

// Check if successful (2xx status)
if ($response->successful()) {
    echo "Request succeeded!";
}

// Alias for successful() with shorter syntax
if ($response->success()) {
    $data = $response->json();
}

// Check if failed (4xx or 5xx status)
if ($response->failed()) {
    echo "Request failed!";
}

// Check if error (alias for failed())
if ($response->isError()) {
    echo "Request has error!";
}

// Get status code
$status = $response->status(); // e.g., 200, 404, 500
```

**Error Type Checks:**

```
// Check for client errors (4xx)
if ($response->isClientError()) {
    echo "Client error: " . $response->status();
}

// Check for server errors (5xx)
if ($response->isServerError()) {
    echo "Server error: " . $response->status();
}

// Check for redirects (3xx)
if ($response->isRedirect()) {
    echo "Redirect to: " . $response->header('Location');
}
```

**Specific Status Code Checks:**

```
// Success codes
$response->isOk();                    // 200 OK
$response->isCreated();               // 201 Created
$response->isNoContent();             // 204 No Content

// Client error codes
$response->isBadRequest();            // 400 Bad Request
$response->isUnauthorized();          // 401 Unauthorized
$response->isForbidden();             // 403 Forbidden
$response->isNotFound();              // 404 Not Found
$response->isUnprocessableEntity();   // 422 Unprocessable Entity
$response->isTooManyRequests();       // 429 Too Many Requests

// Server error codes
$response->isInternalServerError();   // 500 Internal Server Error
```

**Example Usage:**

```
$response = Http::get('https://api.example.com/users/123');

if ($response->isNotFound()) {
    echo "User not found!";
} elseif ($response->isUnauthorized()) {
    echo "Authentication required!";
} elseif ($response->isServerError()) {
    echo "Server error occurred!";
} elseif ($response->success()) {
    $user = $response->json();
    echo "User: " . $user['name'];
}
```

**Throw on Failure:**

You can throw an exception automatically if the response failed:

```
use ElliePHP\Components\HttpClient\Http;
use ElliePHP\Components\HttpClient\RequestException;

try {
    // This will throw RequestException if response is 4xx or 5xx
    $response = Http::get('https://api.example.com/users')
        ->throw();

    $data = $response->json();
} catch (RequestException $e) {
    echo "Request failed: " . $e->getMessage();
}
```

**Get JSON or Throw:**

For convenience, you can get JSON directly and throw if failed:

```
use ElliePHP\Components\HttpClient\Http;
use ElliePHP\Components\HttpClient\RequestException;

try {
    // This will throw RequestException if response is not successful
    $data = Http::get('https://api.example.com/users')
        ->jsonOrFail();

    // Or get a specific key
    $name = Http::get('https://api.example.com/users/123')
        ->jsonOrFail('name');
} catch (RequestException $e) {
    echo "Request failed: " . $e->getMessage();
}
```

#### Access Response Data

[](#access-response-data)

```
use ElliePHP\Components\HttpClient\Http;

$response = Http::get('https://api.example.com/users');

// Get raw body
$body = $response->body();

// Get JSON data
$data = $response->json();

// Get specific JSON key
$name = $response->json('name');
```

#### Access Response Headers

[](#access-response-headers)

```
use ElliePHP\Components\HttpClient\Http;

$response = Http::get('https://api.example.com/users');

// Get all headers
$headers = $response->headers();

// Get specific header
$contentType = $response->header('Content-Type');
$rateLimit = $response->header('X-RateLimit-Remaining');
```

### Error Handling

[](#error-handling)

The library throws `RequestException` for network errors and timeouts:

```
use ElliePHP\Components\HttpClient\Http;
use ElliePHP\Components\HttpClient\RequestException;

try {
    $response = Http::get('https://api.example.com/users');

    if ($response->successful()) {
        $data = $response->json();
        // Process data
    } else {
        // Handle 4xx/5xx responses
        echo "HTTP Error: " . $response->status();
    }
} catch (RequestException $e) {
    // Handle network errors, timeouts, etc.
    echo "Request failed: " . $e->getMessage();

    // Access original exception if needed
    $previous = $e->getPrevious();
}
```

#### Exception Types

[](#exception-types)

The library handles these types of errors:

- Network Errors: Connection failures, DNS resolution errors, SSL errors
- Timeout Errors: Request exceeds configured timeout
- Transport Errors: Other Symfony transport level errors

Note that 4xx and 5xx HTTP responses do NOT throw exceptions by default. Use `$response->successful()` or `$response->failed()` to check status.

Method Chaining
---------------

[](#method-chaining)

All configuration methods return a `ClientBuilder` instance, allowing fluent method chaining:

```
// Using Http facade
$response = Http::withBaseUrl('https://api.example.com')
    ->withToken('your-api-token')
    ->withUserAgent('MyApp/1.0')
    ->withTimeout(30)
    ->withMaxRedirects(5)
    ->withRetry([
        'max_retries' => 3,
        'delay' => 1000,
        'multiplier' => 2,
    ])
    ->acceptJson()
    ->asJson()
    ->post('/users', [
        'name' => 'John Doe',
        'email' => 'john@example.com'
    ]);

// Or using HttpClient instance
$client = new HttpClient();
$response = $client
    ->withBaseUrl('https://api.example.com')
    ->withToken('your-api-token')
    ->withTimeout(30)
    ->withRetry([
        'max_retries' => 3,
        'delay' => 1000,
        'multiplier' => 2,
    ])
    ->acceptJson()
    ->asJson()
    ->post('/users', [
        'name' => 'John Doe',
        'email' => 'john@example.com'
    ]);
```

Complete Examples
-----------------

[](#complete-examples)

### Example 1: Simple API Client

[](#example-1-simple-api-client)

```
use ElliePHP\Components\HttpClient\Http;

// Quick one-off requests using Http facade
$users = Http::get('https://api.example.com/users')->json();

foreach ($users as $user) {
    echo $user['name'] . "\n";
}
```

### Example 2: Configured API Client

[](#example-2-configured-api-client)

```
use ElliePHP\Components\HttpClient\HttpClient;
use ElliePHP\Components\HttpClient\RequestException;

class ApiClient
{
    private HttpClient $client;
    private string $apiToken;

    public function __construct(string $apiToken)
    {
        $this->client = new HttpClient();
        $this->apiToken = $apiToken;
    }

    public function getUsers(int $page = 1): array
    {
        try {
            $response = $this->client
                ->withBaseUrl('https://api.example.com')
                ->withToken($this->apiToken)
                ->withUserAgent('MyApp/1.0')
                ->withTimeout(30)
                ->acceptJson()
                ->get('/users', ['page' => $page]);

            if ($response->successful()) {
                return $response->json();
            }

            throw new \Exception('Failed to fetch users: ' . $response->status());
        } catch (RequestException $e) {
            throw new \Exception('API request failed: ' . $e->getMessage(), 0, $e);
        }
    }

    public function createUser(array $userData): array
    {
        try {
            $response = $this->client
                ->withBaseUrl('https://api.example.com')
                ->withToken($this->apiToken)
                ->asJson()
                ->post('/users', $userData);

            if ($response->successful()) {
                return $response->json();
            }

            throw new \Exception('Failed to create user: ' . $response->status());
        } catch (RequestException $e) {
            throw new \Exception('API request failed: ' . $e->getMessage(), 0, $e);
        }
    }
}
```

### Example 3: Resilient API Client with Retries

[](#example-3-resilient-api-client-with-retries)

```
use ElliePHP\Components\HttpClient\Http;

// Configure for resilient API calls using Http facade
$response = Http::withBaseUrl('https://api.example.com')
    ->withToken('your-api-token')
    ->withUserAgent('MyApp/1.0')
    ->withTimeout(30)
    ->withMaxRedirects(5)
    ->withRetry([
        'max_retries' => 3,
        'delay' => 1000,
        'multiplier' => 2,
        'jitter' => 0.1,
        'http_codes' => [429, 500, 502, 503, 504],
    ])
    ->acceptJson()
    ->asJson()
    ->post('/orders', [
        'product_id' => 123,
        'quantity' => 2,
        'customer_id' => 456
    ]);

if ($response->successful()) {
    $order = $response->json();
    echo "Order created: " . $order['id'];
} else {
    echo "Order failed: " . $response->status();
}
```

### Example 4: Using Convenience Methods

[](#example-4-using-convenience-methods)

```
use ElliePHP\Components\HttpClient\Http;

// Chain convenience methods for clean, readable code
$response = Http::withBaseUrl('https://api.example.com')
    ->withUserAgent('MyApp/2.0')
    ->withContentType('application/json')
    ->withAccept('application/json')
    ->withHeader('X-API-Version', 'v2')
    ->withTimeout(30)
    ->withMaxRedirects(3)
    ->withToken('your-api-token')
    ->get('/users');

if ($response->successful()) {
    $users = $response->json();
    // Process users...
}
```

### Example 5: File Upload

[](#example-5-file-upload)

```
use ElliePHP\Components\HttpClient\Http;
use ElliePHP\Components\HttpClient\RequestException;
use InvalidArgumentException;

try {
    // Upload a single file with metadata
    $response = Http::withBaseUrl('https://api.example.com')
        ->withToken('your-api-token')
        ->withUserAgent('MyApp/1.0')
        ->attach('file', '/path/to/document.pdf')
        ->post('/upload', [
            'title' => 'Important Document',
            'category' => 'legal'
        ]);

    if ($response->successful()) {
        $result = $response->json();
        echo "File uploaded: " . $result['file_id'];
    }

    // Upload multiple files
    $response = Http::withBaseUrl('https://api.example.com')
        ->withToken('your-api-token')
        ->attach('avatar', '/path/to/avatar.jpg')
        ->attach('cover', '/path/to/cover.jpg')
        ->post('/upload', [
            'user_id' => 123
        ]);

} catch (InvalidArgumentException $e) {
    echo "File error: " . $e->getMessage();
} catch (RequestException $e) {
    echo "Upload failed: " . $e->getMessage();
}
```

API Reference
-------------

[](#api-reference)

### Http Facade

[](#http-facade)

The `Http` facade provides a static interface that delegates to `HttpClient`. All methods available on `HttpClient` are also available on `Http`.

```
use ElliePHP\Components\HttpClient\Http;

// All HttpClient methods work with Http facade
Http::get('https://api.example.com/users');
Http::withBaseUrl('https://api.example.com')->get('/users');
Http::withToken('token')->get('/api/protected');
```

### HttpClient

[](#httpclient)

#### Static Methods

[](#static-methods)

These methods are for quick, one-off requests without configuration. They expect full, absolute URLs.

- `HttpClient::get(string $url, array $query = []): Response`
- `HttpClient::post(string $url, array $data = []): Response`
- `HttpClient::put(string $url, array $data = []): Response`
- `HttpClient::patch(string $url, array $data = []): Response`
- `HttpClient::delete(string $url): Response`

#### Configuration Methods

[](#configuration-methods)

These methods return a `ClientBuilder` instance for method chaining and properly handle configured requests.

- `withBaseUrl(string $baseUrl): ClientBuilder`
- `withHeaders(array $headers): ClientBuilder`
- `withHeader(string $name, string $value): ClientBuilder`
- `withUserAgent(string $userAgent): ClientBuilder`
- `withContentType(string $contentType): ClientBuilder`
- `withAccept(string $accept): ClientBuilder`
- `withToken(string $token): ClientBuilder`
- `withBasicAuth(string $username, string $password): ClientBuilder`
- `acceptJson(): ClientBuilder`
- `asJson(): ClientBuilder`
- `withTimeout(int $seconds): ClientBuilder`
- `withMaxRedirects(int $maxRedirects): ClientBuilder`
- `withVerify(bool $verify = true): ClientBuilder`
- `withProxy(string $proxyUrl): ClientBuilder`
- `withRetry(array $retryConfig): ClientBuilder`
- `withOptions(array $options): ClientBuilder`
- `attach(string $name, string|resource $file): ClientBuilder`

#### Request Methods on Instance

[](#request-methods-on-instance)

These methods work on the HttpClient instance but require full URLs when called directly without configuration chaining.

- `get(string $url, array $query = []): Response`
- `post(string $url, array $data = []): Response`
- `put(string $url, array $data = []): Response`
- `patch(string $url, array $data = []): Response`
- `delete(string $url): Response`

### Response

[](#response)

#### Status Methods

[](#status-methods)

**General Status Checks:**

- `status(): int`
- `successful(): bool`
- `success(): bool`
- `failed(): bool`
- `isError(): bool`
- `throw(): self`
- `jsonOrFail(?string $key = null): mixed`

**Error Type Checks:**

- `isClientError(): bool`
- `isServerError(): bool`
- `isRedirect(): bool`

**Specific Status Code Checks:**

- `isOk(): bool`
- `isCreated(): bool`
- `isNoContent(): bool`
- `isBadRequest(): bool`
- `isUnauthorized(): bool`
- `isForbidden(): bool`
- `isNotFound(): bool`
- `isUnprocessableEntity(): bool`
- `isTooManyRequests(): bool`
- `isInternalServerError(): bool`

#### Content Methods

[](#content-methods)

- `body(): string`
- `json(?string $key = null): mixed`
- `headers(): array`
- `header(string $name): ?string`

### RequestException

[](#requestexception)

Custom exception thrown for network errors, timeouts, and transport failures.

```
use ElliePHP\Components\HttpClient\Http;
use ElliePHP\Components\HttpClient\RequestException;

try {
    $response = Http::get('https://api.example.com/data');
} catch (RequestException $e) {
    echo $e->getMessage();
    echo $e->getCode();
    $previous = $e->getPrevious();
}
```

Testing
-------

[](#testing)

Run the test suite:

```
composer test
```

Run tests with coverage:

```
composer test:coverage
```

License
-------

[](#license)

This library is open-sourced software licensed under the MIT license.

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

[](#contributing)

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

Support
-------

[](#support)

- Issues: GitHub Issues
- Source: GitHub Repository

Credits
-------

[](#credits)

Built on top of Symfony HttpClient.

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance82

Actively maintained with recent releases

Popularity12

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity58

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

Recently: every ~19 days

Total

9

Last Release

100d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/cbee85b8c11aa5cf87d8d91eb6ec1ff7e11aa3ee59c939199d5d99a40603a6cf?d=identicon)[joeyboli](/maintainers/joeyboli)

---

Top Contributors

[![joeyboli](https://avatars.githubusercontent.com/u/43940776?v=4)](https://github.com/joeyboli "joeyboli (14 commits)")

---

Tags

httpclientelliephp

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/elliephp-httpclient/health.svg)

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

PHPackages © 2026

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