dormilich/http-client
Lightweight PHP HTTP client wrapper focused on simple requests and responses, with a clean API for common HTTP methods and header/body handling. Useful as a minimal dependency for sending HTTP calls without a full-featured framework.
Installation
composer require dormilich/http-client
Add the package to your config/app.php providers (if not auto-discovered):
Dormilich\HttpClient\Providers\HttpClientServiceProvider::class,
Basic Usage
Register the HTTP client in your service container (e.g., AppServiceProvider):
use Dormilich\HttpClient\Client;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
public function register()
{
$this->app->singleton(Client::class, function ($app) {
return new Client(
$app->make(RequestFactoryInterface::class),
$app->make(StreamFactoryInterface::class),
$app->make(\Psr\Http\Client\ClientInterface::class)
);
});
}
First Request
Inject Client into a controller or service and make a request:
use Dormilich\HttpClient\Client;
public function fetchData(Client $client)
{
$response = $client->request('GET', 'https://api.example.com/data');
$body = $response->getBody()->getContents();
return json_decode($body, true);
}
Key Classes to Explore
Client: Main facade for HTTP requests.Response: Handles response parsing and data extraction.Request: Builds and configures requests.Chain middleware for request/response transformations:
$client->withMiddleware([
new \Dormilich\HttpClient\Middleware\AddHeader('X-Custom-Header', 'value'),
new \Dormilich\HttpClient\Middleware\JsonEncode(),
])->request('POST', 'https://api.example.com', ['key' => 'value']);
Create a service to encapsulate request logic:
class ApiService {
protected $client;
public function __construct(Client $client)
{
$this->client = $client;
}
public function getUser($id)
{
return $this->client->request('GET', "/users/{$id}");
}
}
Parse responses with helper methods:
$response = $client->request('GET', 'https://api.example.com/data');
$data = $response->json(); // Auto-decodes JSON
$status = $response->getStatusCode();
Use exceptions or custom logic:
try {
$response = $client->request('GET', 'https://api.example.com/nonexistent');
} catch (\Psr\Http\Client\NetworkExceptionInterface $e) {
// Handle network errors
} catch (\Dormilich\HttpClient\Exception\RequestException $e) {
// Handle HTTP errors (4xx, 5xx)
}
Mock the ClientInterface for unit tests:
$mockClient = $this->createMock(\Psr\Http\Client\ClientInterface::class);
$this->app->instance(\Psr\Http\Client\ClientInterface::class, $mockClient);
Client anywhere.config/http-client.php.events() in the ServiceProvider).GuzzleHttp\Client, Symfony\HttpClient). Ensure your PSR-18 client is properly bound in the container.delay, timeout options).No Built-in Retries
retry middleware).Response Parsing Assumptions
json() assume the response is JSON. Validate content-type or handle exceptions:
if ($response->getHeaderLine('Content-Type') !== 'application/json') {
throw new \RuntimeException('Unexpected content type');
}
Stream Handling
$response = $client->request('GET', 'https://example.com/large-file');
file_put_contents('file.pdf', $response->getBody());
Middleware Order
$client->withMiddleware([
new AuthMiddleware(),
new LoggingMiddleware(),
]);
Enable Debugging for Underlying Client If using Guzzle, add:
$client->withMiddleware(new \GuzzleHttp\Middleware::tap(function ($request) {
\Log::debug('Request:', [$request->getUri(), $request->getHeaders(), $request->getBody()]);
}));
Check Response Headers
Use getHeaders() to inspect raw headers for clues:
$headers = $response->getHeaders();
Custom Middleware
Implement \Dormilich\HttpClient\Middleware\RequestMiddlewareInterface or \ResponseMiddlewareInterface:
class CustomMiddleware implements RequestMiddlewareInterface {
public function __invoke($request, callable $next) {
$request = $request->withHeader('X-Custom', 'value');
return $next($request);
}
}
Response Decorators
Extend \Dormilich\HttpClient\Response to add custom parsing methods.
Underlying Client Swap
Replace the PSR-18 client binding to use a different implementation (e.g., Symfony’s HttpClient).
No Default Config The package is lightweight and doesn’t ship with config files. All settings are passed via constructor or middleware.
PSR-18 Client Dependencies Ensure your PSR-18 client (e.g., Guzzle) is properly configured for timeouts, proxies, etc., outside this package.
http_defaults).transferStats).How can I help you explore Laravel packages today?