galvesband/http-client

Framework-agnostic HTTP client core package.

Maintainers

Package info

gitlab.com/galvesband-php-packages/http-client

Issues

pkg:composer/galvesband/http-client

Statistics

Installs: 88

Dependents: 0

Suggesters: 0

Stars: 0

v1.0.2 2026-03-12 00:25 UTC

This package is auto-updated.

Last update: 2026-03-11 23:25:31 UTC


README

This package wraps Guzzle with a fluent API that adds lifecycle hooks, named configuration profiles, extended JSON support, and a built-in fake for testing — all without any framework dependency.

Reach for it when you need consistent behavior across every outbound request (logging, metrics, etc.), want to manage multiple API targets under a single factory, or just want better tooling for testing HTTP interactions without real network calls.

The package only requires Guzzle, ext-curl, and ext-json. There is a companion package galvesband/http-client-for-laravel that wires everything into Laravel — facade, container binding, dedicated config file, queue-based async dispatch, database persistence via migrations, and framework events. If you are on Laravel, start there instead.

Requirements

  • PHP: 7.4.* || 8.*
  • PHP extensions: ext-curl, ext-json
  • Runtime dependency: guzzlehttp/guzzle:^7.7

The package uses a CI pipeline that executes tests in PHP >= 7.4 (PHP 8.5 and above still missing but should be supported soon) and runs phpstan.

Installation

This is a standard packagist package. You can install it in your project with:

composer require galvesband/http-client

Start using it by importing the factory and defining a default profile and options. Then do requests directly (by using the default profile) or in a specific profile.

use Galvesband\HttpClient\Factories\ClientFactory;
use Galvesband\HttpClient\Factories\SinkFactory;

// Build a factory somewhere in your start-up phase with your desired configuration.
$factory = new ClientFactory([
    // What profile use by default, if no profile is specified
    'default_profile' => 'default',
    // Default profile options; if the profile doesn't define an option, the default from this will be used
    'profile_defaults' => ['connect_timeout' => 10, 'timeout' => 20, 'sinks' => []],
    'profiles' => [
        // Definition of "default" profile. Will inherit all "profile_defaults" options.
        'default' => [],
        // Definition of another profile with specific options. 
        'example-profile' => ['base_uri' => 'https://api.example.test', 'connect_timeout' => 15, 'timeout' => 30],
    ],
], new SinkFactory([]));

// Use the factory to make a request through the "default" profile.
// The string in `newRequest()` acts as a label or description of the request.
$responseFromDefaultProfile = $factory->newRequest('health-check')
    ->to('GET', 'https://api.example.test/health')
    ->execute();

// Use the factory with a specific profile to use its options by default
$responseFromExampleProfile = $factory->profile('example-profile')->newRequest('health-check')
    // Full url is not needed as it is defined in the profile. Timeout will be overridden too.
    ->to('GET', '/health')
    ->execute();

// You can get the Guzzle client from a profile and make requests directly.
// Useful when you have code that already uses Guzzle directly.
// The trade-off: per-request labels are not available this way.
$guzzleClient = $factory->profile('example-profile')->getInternalClient();

Worth knowing: the SinkFactory passed to the factory is where sinks come from. Each attached sink automatically receives the result of every request made through its profile — a handy hook for logging, metrics, or persisting requests to a database. See Sinks and extractors for the full picture.

For a complete setup walkthrough, see Installation and first success.

How it works

The clients built by the factory carry a custom Guzzle middleware that intercepts each outgoing request. This is how profile-specific options (base URI, timeouts, headers) are applied, and how sinks receive the request result after execution.

The Sink contract is built on top of that mechanism. A profile can attach one or more sinks, and after each request completes, every attached sink gets the full request/response payload. Common uses: writing structured logs, persisting request records to a database, feeding metrics to a Prometheus exporter.

Documentation

License

MIT. See LICENSE.

Validation

composer install
composer test
composer stan

You can run this commands in any supported PHP version with ext-curl and ext-json.

The pipeline and the recommended development environment is provided as a docker set-up in .docker/. The recommended way to execute tests and other commands is the following:

docker compose -f .docker/docker-compose.yml run -it --rm app vendor/bin/phpunit # or any other php command

In the docker-compose.yml file are services defined for each supported PHP version.