Installation
composer require tuupola/http-factory
The package auto-discovers HTTP factories via Laravel's service provider system—no manual configuration is required.
First Use Case: Creating an HTTP Client
use Tuupola\Http\Factory;
$client = Factory::createClient();
This leverages Laravel's default HTTP client (Guzzle by default) unless overridden.
Where to Look First
config/http-factory.php (if customization is needed).Tuupola\Http\Factory (core methods: createClient(), createStream(), createUri()).HttpClientFactoryInterface, StreamFactoryInterface, and UriFactoryInterface.PSR-17 Factory Integration
Use the factory to create PSR-17 compliant objects (e.g., Uri, Stream, HttpClient) for consistency across Laravel apps:
$uri = Factory::createUri('https://example.com');
$stream = Factory::createStream(fopen('php://memory', 'r+'));
$client = Factory::createClient(['timeout' => 5.0]);
Dependency Injection
Bind the factory to Laravel's container in AppServiceProvider for reusable access:
$this->app->singleton(\Tuupola\Http\Factory::class, function ($app) {
return new \Tuupola\Http\Factory();
});
Then inject via constructor:
public function __construct(private Factory $factory) {}
Custom Factories Extend the factory to support custom implementations (e.g., a mock HTTP client for testing):
class CustomFactory extends \Tuupola\Http\Factory {
public function createClient(array $config = []): HttpClientInterface {
return new MockHttpClient(); // Custom implementation
}
}
Dynamic Configuration
Override default configurations via config/http-factory.php:
'default' => [
'client' => [
'timeout' => 10.0,
'headers' => ['User-Agent' => 'MyApp/1.0'],
],
],
Factory::createClient() to standardize HTTP client creation across services.$this->app->bind(\Tuupola\Http\Factory::class, function () {
return new CustomFactory(); // Mock factory
});
$client = Factory::createClient();
$client->getEmitter()->attach(
new \GuzzleHttp\Middleware::retry(RetryMiddleware::defaults())
);
Auto-Discovery Conflicts
If multiple packages implement HttpClientFactoryInterface, the last registered factory wins. Explicitly bind your factory to avoid surprises:
$this->app->bind(\Tuupola\Http\Factory::class, function () {
return new \Tuupola\Http\Factory();
});
Stream Handling
The createStream() method returns a Psr\Http\Message\StreamInterface, not a native PHP stream. Ensure compatibility when passing streams to non-PSR-17 code:
$stream = Factory::createStream(fopen('file.txt', 'r'));
if (!$stream instanceof \Psr\Http\Message\StreamInterface) {
throw new \RuntimeException('Stream is not PSR-17 compliant');
}
Configuration Overrides
Config values in config/http-factory.php are merged with runtime arguments. Runtime args take precedence:
$client = Factory::createClient(['timeout' => 2.0]); // Overrides config
Factory Instantiation Issues
If Factory::createClient() fails, check:
HttpClientFactoryInterface implementation (e.g., Guzzle's Client).Stream Resource Leaks Always close streams explicitly or use context managers:
$stream = Factory::createStream(fopen('file.txt', 'r'));
try {
// Use stream
} finally {
$stream->close();
}
Custom Factories
Override methods like createUri() or createStream() in a subclass:
class CustomFactory extends \Tuupola\Http\Factory {
public function createUri(string $uri = '', array $parts = []): UriInterface {
return new \Laminas\Diactoros\Uri($uri); // Use Laminas instead of default
}
}
Dynamic Factory Resolution
Use Laravel's resolve() method to dynamically switch factories:
$factory = app()->make(\Tuupola\Http\Factory::class, ['config' => 'custom']);
Testing Utilities Create a test helper to reset the factory:
function mockHttpFactory() {
$this->app->bind(\Tuupola\Http\Factory::class, function () {
return new CustomFactory(); // Reset to mock
});
}
How can I help you explore Laravel packages today?