ottsch/http-adapter-bundle
A Symfony bundle for integrating configurable HTTP adapters, making it easy to send HTTP requests through dependency-injected client services. It centralizes adapter configuration and simplifies HTTP transport setup in Symfony applications.
composer require ottsch/http-adapter-bundle. It keeps the original Widop\... namespaces, so register Widop\Bundle\HttpAdapterBundle\WidopHttpAdapterBundle in config/bundles.php (or AppKernel::registerBundles()).# config/packages/widop_http_adapter.yaml
widop_http_adapter:
adapter: curl # or "stream"
widop.http.adapter, an instance of Widop\HttpAdapter\HttpAdapterInterface. Type-hint the interface, not the concrete class.$response = $adapter->get('https://api.example.com/v1/status', [
'Accept: application/json',
]);
if ($response->getStatusCode() === 200) {
$data = json_decode($response->getBody(), true);
}
DependencyInjection/Configuration.php in the bundle (it confirms the only config is the adapter choice), then the vendor widop/http-adapter source for the exact HttpAdapterInterface and HttpResponse signatures. Do not guess the method signatures from memory — the library predates PSR-18 and its conventions are non-standard.final class AcmeApiClient
{
public function __construct(
private HttpAdapterInterface $adapter,
private string $token,
) {}
public function fetchUser(int $id): array
{
$response = $this->adapter->get(
sprintf('https://api.acme.test/users/%d', $id),
['Accept: application/json', 'Authorization: Bearer '.$this->token]
);
if ($response->getStatusCode() >= 400) {
throw new AcmeApiException($response->getStatusCode(), $response->getBody());
}
return json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR);
}
}
services:
App\Http\AcmeApiClient:
arguments: ['@widop.http.adapter', '%env(ACME_TOKEN)%']
$response = $adapter->post(
'https://api.acme.test/users',
['Content-Type: application/json', 'Accept: application/json'],
json_encode(['name' => 'Ada'], JSON_THROW_ON_ERROR)
);
HttpAdapterInterface (remember it has six methods: get, head, post, put, patch, delete), or retry around a single call inside the domain client — the latter is simpler and usually preferable.Widop\HttpAdapter\HttpAdapterInterface and use a hand-written fake that returns Widop\HttpAdapter\HttpResponse instances. Verify the constructor argument order against your installed version before relying on it in tests.error_log at call sites.symfony/http-client. Reach for this only in a legacy codebase that already depends on it.stream adapter requires allow_url_fopen=1 and respects default_socket_timeout; it is slower and less featureful. Use curl in production unless the extension is unavailable."Name: value" strings, not associative arrays, and set Accept/Content-Type yourself — do not assume defaults.getStatusCode(). Transport-level failures throw Widop\HttpAdapter\HttpAdapterException — catch around every call.getBody(), getHeaders(), getStatusCode(). Header parsing for Content-Type, Location, and pagination links is your responsibility.curl -v using the same URL and headers, or add the decorator described above.widop.http.adapter service definition/alias in your own service config with a custom HttpAdapterInterface implementation (timeouts, retries, logging) — call sites stay untouched.Widop\... namespaces and the widop_http_adapter config root. Do not also composer require widop/http-adapter separately, or you risk duplicate class definitions.How can I help you explore Laravel packages today?