paysera/lib-rest-client-common
This package supplies the shared abstractions behind Paysera's PHP REST client libraries: HTTP transport, request signing/authentication, response decoding, error and exception mapping, and reusable data mappers, helping integrations stay consistent, testable, and maintainable.
2.8.0 or later:
composer require <vendor>/<package>:^2.8
ClientFactoryAbstract — the base factory you extend to build Guzzle clients.GuzzleMiddlewareInterface — the new contract for injectable Guzzle middleware.Minimal first use case:
use Vendor\Package\ClientFactoryAbstract;
use GuzzleHttp\Client;
class BillingClientFactory extends ClientFactoryAbstract
{
protected function baseUri(): string
{
return config('services.billing.base_uri');
}
protected function defaultHeaders(): array
{
return [
'Accept' => 'application/json',
];
}
}
// Bind it once in a service provider.
$this->app->singleton(BillingClientFactory::class);
// Inject the factory, not a pre-built client, where you need it.
public function __construct(private BillingClientFactory $factory) {}
$client = $this->factory->make();
The first practical win in 2.8.0 is that middleware no longer needs to be wired manually every time you construct a client. Implement GuzzleMiddlewareInterface once and inject it into the factory.
Implement the new interface for cross-cutting concerns:
use Vendor\Package\GuzzleMiddlewareInterface;
use Psr\Http\Message\RequestInterface;
class AddCorrelationId implements GuzzleMiddlewareInterface
{
public function __invoke(callable $handler): callable
{
return function (RequestInterface $request, array $options) use ($handler) {
return $handler(
$request->withHeader('X-Correlation-Id', (string) Str::uuid()),
$options
);
};
}
}
Then inject it through the factory’s middleware configuration rather than wrapping the client after construction. This keeps the middleware stack consistent across every client the factory produces.
Use separate factory subclasses or factory configuration for different upstream services. A payments client usually needs retry, idempotency, and strict timeouts; a reporting client may only need logging. Keeping middleware scoped to the factory avoids accidentally applying auth middleware to unrelated hosts.
Typical split:
AuthMiddleware — token or HMAC signing.RetryMiddleware — only for idempotent requests.LogMiddleware — request/response logging with redaction.CorrelationMiddleware — trace IDs propagated to upstream services.Prefer injecting ClientFactoryAbstract subclasses into services and jobs, then calling the factory when the client is needed. This lets middleware and config be resolved from the container at request time and makes testing easier. Avoid binding a fully constructed GuzzleHttp\Client as a singleton unless the client is truly stateless and config-independent.
Use Guzzle’s MockHandler and HandlerStack in tests, and assert that your middleware is present in the stack:
$mock = new MockHandler([new Response(200, [], '{"ok":true}')]);
$stack = HandlerStack::create($mock);
$stack->push(new AddCorrelationId());
$client = new Client(['handler' => $stack]);
For factory-level tests, resolve the factory from the container and assert the produced client sends the expected headers or retries as configured.
2.8.0 adds middleware injection to ClientFactoryAbstract. If you subclass the factory and override its constructor without calling parent::__construct(), injected middleware may be silently skipped.php artisan config:clear during debugging. Cached config can make it look like your new middleware class is not being picked up.GuzzleMiddlewareInterface exactly as defined by the package. Guzzle’s own MiddlewareInterface is similar but not necessarily interchangeable; type-hint the package contract where the factory expects it.Authorization, cookies, and signed query parameters before writing to logs.HandlerStack. Keep custom stack manipulation in one subclass rather than scattering it across services.^2.8 and run your integration tests against the new middleware injection path before rolling out broadly.How can I help you explore Laravel packages today?