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

Guzzle Config Operations Bundle Laravel Package

pierrerolland/guzzle-config-operations-bundle

Symfony bundle that simplifies Guzzle HTTP client configuration by letting you define and manage client settings through Symfony configuration. It helps keep HTTP client setup consistent and reusable across services, reducing boilerplate for projects that rely on Guzzle.

View on GitHub
Deep Wiki
Context7

Getting Started

Before you install, check survivability. This package's last release is 2019-04-17, with 3 stars and 0 dependents. That means it was written against Symfony 3.4/4.x and Guzzle 6, and almost certainly has no PHP 8 return-type annotations, no symfony/deprecation-contracts, and possibly hard version constraints that conflict with Guzzle 7. Start with:

composer require pierrerolland/guzzle-config-operations-bundle --dry-run

If the resolver fights you, you're looking at constraint surgery or a fork — decide that before you write code against it.

Minimal setup (Symfony 4/Flex era):

  1. composer require pierrerolland/guzzle-config-operations-bundle
  2. Register the bundle in config/bundles.php:
    Pierrerolland\GuzzleConfigOperationsBundle\GuzzleConfigOperationsBundle::class => ['all' => true],
    
    The exact FQCN is the one thing worth confirming from the repo's README/composer.json autoload block — get it wrong and you get a silent "no services" instead of an error.
  3. Discover the actual config shape rather than guessing it:
    bin/console config:dump-reference guzzle_config_operations
    
    The alias may differ; find it with bin/console debug:config --help or by grepping the bundle's DependencyInjection/Configuration.php.

Where to look first, in this order:

File Why it matters
DependencyInjection/Configuration.php The config tree. This is the documentation — keys, nesting, defaults, required fields.
DependencyInjection/*Extension.php How your YAML becomes service definitions; tells you the service IDs and whether clients get public/private aliases.
Resources/config/services.xml (or .yaml) Base service IDs and tags you can decorate or override.
Tests/ With 3 stars there's likely no docs site; the test fixtures are the real usage examples.
composer.json Actual Guzzle/Symfony constraint ranges — decides whether this is viable at all.

First use case. Don't start with your whole API surface. Define one client with one operation, inject it, and make a call:

# config/packages/guzzle_config_operations.yaml  (illustrative — confirm keys)
guzzle_config_operations:
    clients:
        billing:
            base_uri: 'https://billing.internal'
            timeout: 5.0
            operations:
                get_invoice:
                    method: GET
                    uri: 'invoices/{invoiceId}'

Then bin/console debug:container guzzle --show-private to see what service ID you actually got, and inject that. The whole point of the bundle is that the client is a container-managed service, so autowire should work once you know the ID.

Implementation Patterns

Treat the config as an operation registry, not as a client factory. The bundle's value proposition is "reusable, composable config operations" — so the idiomatic use is one YAML block per upstream API, listing every operation you call against it, with stable names. Code then refers to operations by name instead of rebuilding URLs inline. This is what makes the package worth a look: the operation list becomes a reviewable contract for what your app does to a third party.

One file per upstream. config/packages/http/billing.yaml, config/packages/http/shipping.yaml. With many clients, a single monolith YAML becomes unreviewable, and per-file config also gives you clean per-environment overrides:

# config/packages/test/http/billing.yaml
guzzle_config_operations:
    clients:
        billing:
            base_uri: 'http://localhost:8080'   # WireMock / MockServer

That's the most underrated use of a config-driven client: the operation definitions stay byte-identical between dev, test, and prod, and only the transport target changes.

Wrap it, don't leak it. The bundle's services are Guzzle clients. Don't inject a raw Guzzle client into a domain service — inject it into a thin gateway class in your own namespace:

final class BillingGateway
{
    public function __construct(private ClientInterface $billingClient) {}

    public function invoice(string $id): array
    {
        return json_decode(
            (string) $this->billingClient->request('GET', "invoices/{$id}")->getBody(),
            true,
            512,
            JSON_THROW_ON_ERROR
        );
    }
}

Wire the bundle's client into it via a named alias in services.yaml. Two benefits: if you later migrate to symfony/http-client (which you probably will), you rewrite one class; and your domain tests can fake BillingGateway without touching PSR-18 plumbing.

Environment-scoped parameters via %env()%, deliberately. Base URIs and credentials belong in env, referenced as '%env(BILLING_BASE_URI)%'. Note that env resolution timing matters — see gotchas.

Middleware/handler stack is the extension seam. Auth headers, correlation IDs, retry, and logging are all HandlerStack middlewares. Build them as small tagged services and push them onto each client's stack in a compiler pass or a small factory service, rather than copy-pasting YAML per client. If the bundle exposes a handler/middleware config key, that's your hook; if not, decorate the client service.

Testing. Use GuzzleHttp\Handler\MockHandler in a test-environment service definition that swaps the handler, so the operation config under test is the production config. Queue responses and assert on $mock->getLastRequest(). This is cheap and catches the config errors (typo'd base_uri, wrong method) that a mocked gateway would hide.

Composability tip. If the bundle supports multiple config files or a fragment mechanism, lean on it for shared defaults (timeouts, user-agent, retry policy) and keep per-API files limited to what's genuinely different. Duplicated timeout: 5.0 across twelve files is how these setups rot.

Gotchas and Tips

Maintenance risk is the headline gotcha. Last release 2019, 3 stars, 0 dependents. Expect: no PHP 8.1+ #[ReturnTypeWillChange] fixes, Guzzle 6 type signatures (e.g. ClientInterface::request signatures changed subtly), Symfony 5/6 removal of ContainerBuilder APIs it may use. Pin it ("pierrerolland/guzzle-config-operations-bundle": "dev-master#<sha>") and treat it as vendored code you own. If you need more than a week's friction to make it run, the honest answer is that eightpoints/guzzle-bundle or plain PSR-18 with symfony/http-client will cost less.

The config tree is undocumented — introspect it, don't infer it. bin/console config:dump-reference <alias> and bin/console debug:config <alias> are the only reliable sources. Guessing YAML keys from the package name will burn an afternoon on "Unrecognized option" errors.

Config cache in prod. Symfony compiles extension config into the container cache. Editing YAML on a running production box does nothing until bin/console cache:clear (or a deploy that rebuilds). Symptom: "I changed the base URI and it's still hitting staging." Also ensure var/cache is writable by the deploy user — permission errors here surface as confusing missing-service exceptions.

%env()% resolution timing. Env vars referenced in bundle config are resolved at container compile time in most setups, not per-request. If you need a per-environment base URI that isn't known at build time, this is a landmine — the value gets baked into the compiled container. Confirm whether the bundle defers resolution; if not, build separate container caches per environment, or move the dynamic part into a middleware.

Secrets. Don't inline API tokens in YAML that lands in git. Use %env(BILLING_TOKEN)%, Symfony secrets vault, or a token-provider middleware. A token in a compiled container cache is also readable by anything that can read var/cache.

Debugging failed requests. In order: debug:container --show-private | grep -i guzzle to confirm the service exists and get its ID; check the handler is CurlHandler not StreamHandler if you see weird SSL/timeout behaviour; enable GuzzleHttp\Middleware::history and log $transferTime/$effectiveUri. Guzzle's exception messages truncate the body — catch RequestException, read getResponse()->getBody() before it's consumed.

Guzzle's default timeout is none. If the bundle doesn't inject timeout/connect_timeout defaults, a stalled upstream will hang your PHP workers until max_execution_time. Set both explicitly in every client block; this is the single most common production incident in Guzzle setups.

Overriding services: decorate, don't replace. The extension registers services under IDs you don't control. Use decorates: in services.yaml so you keep the bundle's wiring; replacing by ID breaks silently when the bundle changes its naming scheme.

Extension points worth knowing. Look for tagged services or a factory interface for custom client/operation construction, and a compiler pass for programmatically registering operations (useful when operations are generated from an OpenAPI spec). If neither exists, the config tree is your only seam — which argues for keeping your gateway layer thick.

When not to use it. For one or two HTTP clients, this bundle is strictly more moving parts than new Client([...]) in a service definition. Its value only amortizes across many clients with overlapping operation sets — and given its age, "many clients" is exactly the scenario where you'd rather not be on unmaintained code.

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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core
nodisrupt/laravel-agent
sierratecnologia/media-manager