Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Http Client Bundle Laravel Package

setono/http-client-bundle

Setono HttpClientBundle integrates a configurable HTTP client into Symfony applications, providing an injectable service for making outbound requests with centralized configuration, sensible defaults, and clean dependency injection.

View on GitHub
Deep Wiki
Context7

Getting Started

First, the framing: this is a Symfony bundle, not a Laravel package. There is no service provider, no auto-discovery, no config/http_client.php. If you are working in a Laravel codebase you will be hand-wiring everything it does, and in most cases you should just skip it and use symfony/http-client (or Laravel's Http facade) directly. The bundle is archived, has 1 star, 0 dependents, and its last release was June 2022 — treat it as vendor code you are adopting, not a dependency you are consuming.

That said, if you are in a Symfony app (or a Laravel app that already pulls in Symfony components), the shape of the package is:

  1. Read the diff, not the README. Before installing, open src/DependencyInjection/Configuration.php and src/DependencyInjection/SetonoHttpClientExtension.php in the repo. The entire public API of a bundle like this is its config tree plus the service IDs it registers. Roughly 10 minutes of reading tells you everything; the docs (if any) will be thinner than the code.
  2. Install:
    composer require setono/http-client-bundle
    
    Then register it explicitly in config/bundles.php:
    Setono\HttpClientBundle\SetonoHttpClientBundle::class => ['all' => true],
    
  3. Configure a named client — the core use case is "I have one API I call repeatedly and I don't want to repeat base_uri and auth headers at every call site":
    # config/packages/setono_http_client.yaml
    setono_http_client:
        clients:
            acme:
                base_uri: 'https://api.acme.test/v1/'
                headers:
                    Accept: 'application/json'
    
    Exact key names must be confirmed against Configuration.php — this is the part most likely to have drifted.
  4. First use case: inject Symfony\Contracts\HttpClient\HttpClientInterface (or the scoped/named alias the bundle exposes) into a service and make one ->request('GET', 'widgets') call. If that round-trips with the correct host and headers, you have validated the bundle. If it does not, stop — you have lost nothing, because the underlying ScopingHttpClient does the same job in three lines.

Laravel translation if you insist on it: in AppServiceProvider::register(), bind HttpClientInterface to Symfony\Component\HttpClient\HttpClient::create([...defaults...]), and register one named binding per upstream API. You get 95% of the value with none of the abandoned-bundle risk.

Implementation Patterns

Named client per upstream, injected by alias. The pattern the bundle is built around is one configured client per third-party service, resolved by name rather than by constructing options inline. In Symfony this is autowiring by argument name or a service alias; in Laravel, contextual binding:

$this->app->when(AcmeGateway::class)
    ->needs(HttpClientInterface::class)
    ->give(fn () => HttpClient::create([
        'base_uri' => config('services.acme.base_uri'),
        'headers'  => ['Accept' => 'application/json'],
    ]));

Note the trailing slash on base_uri — Symfony resolves relative paths against it, and https://api.acme.test/v1 without the slash will drop v1 when you request widgets.

Wrap the client in a gateway class, always. Do not let HttpClientInterface leak into controllers or jobs. The bundle gives you a configured transport; your domain code should see AcmeGateway::listWidgets(): array. This is what makes the package replaceable — when you inevitably rip it out, you change one constructor.

Layer auth and retries as decorators, not config. Symfony's HTTP client composes well: ScopingHttpClient, RetryableHttpClient, TraceableHttpClient. Rather than hunting for whether this bundle supports retry config (it probably does not, given its age), decorate:

$client = new RetryableHttpClient(
    new ScopingHttpClient($inner, $scopes, 'https://api.acme.test'),
    maxRetries: 2
);

This is the extension point that survives the bundle being archived.

Mock at the transport, not the gateway. Symfony's MockHttpClient with a MockResponse queue is the idiomatic test double; it asserts on URL, method, and body without touching the network. In Laravel, Http::fake() covers the Http facade but not an injected HttpClientInterface, so if you adopt this bundle you must test with MockHttpClient and lose Http::fake()'s ergonomics. That is a real day-to-day cost.

Configuration-driven environment switching. Keep base_uri in config per environment (sandbox vs. production) so no code path hardcodes a host. With the bundle this is the YAML file; without it, config/services.php + a binding.

Gotchas and Tips

  • It is archived. No security fixes, no Symfony 6/7 compatibility work. Check composer.json's symfony/* constraints before you require it — a 2022 bundle very likely pins ^4.4|^5.0 and will fight a modern Symfony or a Laravel that ships Symfony 7 components. Composer will tell you immediately; believe it.
  • No Laravel auto-discovery. There is no extra.laravel block. You must register the bundle manually and you are running a Symfony bundle inside Laravel's container, which means Kernel-style bundle bootstrapping does not happen for free. Expect to either use a bundle-bootstrapping shim or give up.
  • Config cache staleness. In Symfony, after editing the YAML you must bin/console cache:clear (or at least warm the container) — a stale compiled container will silently keep old base_uri values and produce baffling "wrong host" bugs.
  • Silent option precedence. With scoped clients, per-request $options merge over configured defaults; arrays like headers merge rather than replace in some paths but not others. When a header "disappears," dump the resolved options before debugging the remote service.
  • Errors are lazy. Symfony's HTTP client does not throw on 4xx/5xx until you call getContent()/getStatusCode(). A bundle that returns a client gives you no protection here — always call getStatusCode() explicitly or wrap in a gateway that does.
  • Debugging: in Symfony, the profiler's HTTP client panel (from symfony/http-client's data collector, not this bundle) is the fastest path. In Laravel there is no such panel — use 'debug' => true on the client plus LoggerInterface decoration, or TraceableHttpClient.
  • Extension points, in order of preference: (1) don't use the bundle — construct ScopingHttpClient yourself; (2) decorate the injected client; (3) subclass/replace the bundle's client factory service definition; (4) fork. Given 1 star and an archived status, options 1–2 are the only ones with a sane maintenance story.
  • License is MIT, so forking or vendoring the ~few-hundred lines into app/Support/ is legally trivial — and probably the right move if you actually want its config ergonomics.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console