christianjbrown / api-client
A thin, strongly-typed PHP 8.5+ client for JSON and XML APIs that wraps GuzzleHttp and normalizes its exceptions into a single, framework-agnostic hierarchy.
Requires
- php: ^8.5
- ext-dom: *
- ext-libxml: *
- ext-simplexml: *
- guzzlehttp/guzzle: ^7.15
- symfony/dependency-injection: ^8.0
Requires (Dev)
- christianjbrown/code-quality-scripts: ^1.0
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^13.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-28 13:21:33 UTC
README
This library provides a simple request client for JSON and XML APIs. It is a wrapper around GuzzleHttp's Client class that decodes responses — JSON to an array, XML to a DOMDocument — and provides common non-Guzzle specific exception classes to make it easier to catch and handle.
✔️ Prerequisites
💡 If you're on MacOS and have Homebrew, PHP and Composer will install with brew install composer.
🏗️ Installation
For your composer-enabled project:
composer require christianjbrown/api-client
💻 Usage
Setup
use ChristianBrown\ApiClient\ApiClient; $apiClient = new ApiClient(); $jsonApiRequestSender = $apiClient->getJsonApiRequestSender(); // or, for XML use // $xmlApiRequestSender = $apiClient->getXmlApiRequestSender();
POST examples
If you need to POST an API endpoint, use post like -
use ChristianBrown\ApiClient\Exception\ExceptionInterface; try { $data = $jsonApiRequestSender->post('url', ['query-string-1-key' => 'query-string-1-value'], [], ['body-key-1' => 'body-value-1']); } catch (ExceptionInterface $e) { print $e->getMessage(); }
GET example
If you need to GET data from an API endpoint, use get like -
use ChristianBrown\ApiClient\Exception\ExceptionInterface; try { $data = $jsonApiRequestSender->get('url', ['query-string-1-key' => 'query-string-1-value'], []); } catch (ExceptionInterface $e) { print $e->getMessage(); }
PUT, PATCH and DELETE
The remaining verbs follow the same shape. put and patch take a body array and send it as JSON;
putForm and patchForm send it as application/x-www-form-urlencoded; delete takes no body.
use ChristianBrown\ApiClient\Exception\ExceptionInterface; try { $data = $jsonApiRequestSender->put('url', [], [], ['body-key-1' => 'body-value-1']); $data = $jsonApiRequestSender->patch('url', [], [], ['body-key-1' => 'body-value-1']); $data = $jsonApiRequestSender->putForm('url', [], [], ['body-key-1' => 'body-value-1']); $data = $jsonApiRequestSender->patchForm('url', [], [], ['body-key-1' => 'body-value-1']); $data = $jsonApiRequestSender->delete('url'); } catch (ExceptionInterface $e) { print $e->getMessage(); }
An endpoint that answers 204 No Content has no JSON body to decode, so reach for the raw
ApiRequestSenderInterface ($apiClient->getApiRequestSender()) for those and ignore the empty
string it returns.
🚨 Error handling
The main value-add of this library is that it catches Guzzle's transport-specific exceptions and
re-throws framework-agnostic ones. Every exception this library throws implements
ChristianBrown\ApiClient\Exception\ExceptionInterface (which extends Throwable), so a single
catch handles all of them:
use ChristianBrown\ApiClient\Exception\ExceptionInterface; try { $data = $jsonApiRequestSender->get('url'); } catch (ExceptionInterface $e) { // any failure from this library print $e->getMessage(); }
To handle specific failure modes, catch the narrower interfaces (all extend ExceptionInterface):
| Interface | Thrown when |
|---|---|
Exception\Request\ConnectExceptionInterface |
The request could not reach the host (DNS/connection failure). |
Exception\Response\BadResponseExceptionInterface |
The API returned a non-2xx status. Exposes getRequest(), getResponse(); the exception code is the HTTP status. |
Exception\Response\TooManyRedirectsExceptionInterface |
The request exceeded the redirect limit. |
Exception\Parse\ParseJsonExceptionInterface |
A JSON request body could not be encoded, or a JSON response could not be decoded. |
Exception\Parse\ParseXmlExceptionInterface |
An XML response could not be parsed. Exposes getErrors() (LibXMLError[]). |
Request/response exceptions expose the PSR-7 getRequest() (and getResponse() for response
errors); parse exceptions expose the failing getMethod(), getUrl(), and getQueryStrings().
📄 License
Released under the MIT License.