widop/http-adapter
Widop HTTP Adapter provides a simple abstraction layer for making HTTP requests in PHP, letting you swap underlying clients (like cURL or other libraries) without changing your code. Useful for libraries and apps that need a lightweight, interchangeable HTTP client.
Installation Add the package via Composer:
composer require widop/http-adapter
Register the service provider in config/app.php:
'providers' => [
Widop\HttpAdapter\ServiceProvider::class,
],
Basic Usage Inject the adapter via Laravel's dependency injection:
use Widop\HttpAdapter\Facades\HttpAdapter;
public function testRequest()
{
$response = HttpAdapter::get('https://api.example.com/data');
return $response->getBody();
}
First Use Case: API Calls Replace Guzzle or Symfony HTTP client calls with this adapter for consistency:
$response = HttpAdapter::post('https://api.example.com/users', [
'json' => ['name' => 'John Doe'],
]);
Service Binding: Prefer binding the adapter to interfaces for testability:
$this->app->bind(
Widop\HttpAdapter\Contracts\HttpAdapter::class,
Widop\HttpAdapter\Adapter::class
);
Facade vs. Injection: Use the HttpAdapter facade for quick scripts, but inject the adapter class in controllers/services for better testing.
Request Configuration Chain methods for fluent configuration:
$response = HttpAdapter::create()
->withHeader('Authorization', 'Bearer token')
->withOption('timeout', 30)
->get('https://api.example.com/endpoint');
Middleware Integration Attach middleware to the adapter for request/response processing:
HttpAdapter::middleware([
new \App\Http\Middleware\LogRequest(),
new \App\Http\Middleware\RetryFailedRequests(),
]);
Async Requests
Use the async() method for non-blocking calls (if supported by the underlying client):
$promise = HttpAdapter::async()->get('https://api.example.com/long-running-task');
$promise->then(function ($response) { /* ... */ });
Retry Logic Implement retry logic via middleware or the adapter’s built-in retry options:
$response = HttpAdapter::withRetry(3, 100)->get('https://api.example.com/flaky-endpoint');
Service Provider: Extend the provider to add custom clients or configurations:
public function register()
{
$this->app->singleton(Widop\HttpAdapter\Contracts\HttpAdapter::class, function ($app) {
return (new Widop\HttpAdapter\Adapter())
->withBaseUri(config('services.api.base_uri'))
->withDefaultHeaders(config('services.api.headers'));
});
}
Config File: Define default configurations in config/http-adapter.php:
return [
'timeout' => 30,
'base_uri' => env('API_BASE_URI'),
'headers' => [
'Accept' => 'application/json',
],
];
PHP 5.3+ Compatibility
match expressions) in middleware or callbacks.create_function() if needed for legacy support.Middleware Execution Order
HttpAdapter::middleware([new A(), new B()]); // B runs first, A last
Response Handling
Widop\HttpAdapter\Response object. Use getBody(), getStatusCode(), or json() methods:
$response = HttpAdapter::get('...');
$data = $response->json(); // Throws exception on non-JSON responses
getStatusCode() before parsing the body to avoid errors.Thread Safety
Enable Verbose Logging Add a middleware to log requests/responses:
HttpAdapter::middleware(new class {
public function handle($request, $next) {
\Log::debug('Request:', $request->toArray());
$response = $next($request);
\Log::debug('Response:', $response->getBody());
return $response;
}
});
Check Underlying Client
The adapter wraps a low-level HTTP client (e.g., curl, stream). Debug issues by inspecting the raw client configuration:
$adapter = HttpAdapter::getAdapter(); // Access the underlying client
Custom Clients
Implement Widop\HttpAdapter\Contracts\HttpClient to integrate alternative HTTP libraries (e.g., ReactPHP):
class CustomClient implements HttpClient {
public function send(Request $request) { /* ... */ }
}
Response Decorators
Extend the Response class to add domain-specific methods:
class ApiResponse extends Widop\HttpAdapter\Response {
public function getUserData() {
return $this->json()['data'];
}
}
Bind it in the service provider:
$this->app->bind(
Widop\HttpAdapter\Response::class,
App\Http\ApiResponse::class
);
Request Factories Create a factory class to standardize request creation:
class ApiRequestFactory {
public static function users() {
return HttpAdapter::create()
->withBasePath('/users')
->withHeader('X-API-Key', config('api.key'));
}
}
Base URI Handling
The adapter does not automatically append a trailing slash to base_uri. Ensure consistency:
// Correct:
HttpAdapter::withBaseUri('https://api.example.com/')->get('users');
// Incorrect (may cause 404):
HttpAdapter::withBaseUri('https://api.example.com')->get('users');
Default Headers
Headers set via withDefaultHeaders() cannot be overridden per-request. Use withHeader() for request-specific overrides:
HttpAdapter::withDefaultHeaders(['User-Agent' => 'MyApp/1.0'])
->withHeader('X-Custom', 'override') // Overrides only for this request
->get('...');
SSL Verification Disable SSL verification only in development (never in production):
HttpAdapter::withOption('verify_peer', false); // Use at your own risk!
How can I help you explore Laravel packages today?