Skip to content

tcds-io/php-jackson-guzzle

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PHP Jackson for Guzzle

PHP Tests

Guzzle integration for tcds-io/php-jackson, a type-safe object mapper inspired by Jackson (Java).

This package provides a typed HTTP client built on top of Guzzle that automatically maps request DTOs into Guzzle options and JSON responses into strongly typed PHP objects, synchronously and asynchronously.


Features

  • Typed object mapping for HTTP responses
  • Request DTO mapping for query params, JSON bodies, and form params
  • Full async support with typed promises
  • Works with immutable and readonly DTOs
  • Keeps the native Guzzle client accessible
  • Built on top of php-jackson for consistent serialization rules

Installation

composer require tcds-io/php-jackson-guzzle

How it works

  1. Create a JacksonClient with a native Guzzle client.
  2. Pass the expected response DTO class to get, post, put, patch, or request.
  3. Optionally pass request DTOs as query params, JSON body, or form params.
  4. Guzzle sends the HTTP request.
  5. PHP-Jackson deserializes the JSON response into your expected DTO.

Basic usage

use GuzzleHttp\Client;
use Tcds\Io\Jackson\Guzzle\JacksonClient;

$client = new JacksonClient(
    new Client([
        'base_uri' => 'https://api.example.com',
    ]),
);

Typed GET

readonly class Address
{
    public function __construct(
        public string $id,
        public string $street,
        public int $number,
        public bool $main,
    ) {}
}

$address = $client->get(Address::class, '/addresses/aaa');

Typed POST with a JSON body

readonly class CreateAddress
{
    public function __construct(
        public string $street,
        public int $number,
    ) {}
}

readonly class AddressCreated
{
    public function __construct(public string $id) {}
}

$created = $client->post(
    class: AddressCreated::class,
    uri: '/addresses',
    jsonBody: new CreateAddress(street: 'Ocean Avenue', number: 42),
);

You can still pass native Guzzle options when needed:

use GuzzleHttp\RequestOptions;

$created = $client->post(
    class: AddressCreated::class,
    uri: '/addresses',
    options: [
        RequestOptions::HEADERS => ['X-Request-ID' => 'abc-123'],
    ],
    jsonBody: new CreateAddress(street: 'Ocean Avenue', number: 42),
);

If an option is already present in options, the client leaves it untouched.


Request data

JacksonClient can serialize DTOs into the common Guzzle request option buckets:

$response = $client->request(
    class: AddressCreated::class,
    method: 'POST',
    uri: '/addresses',
    queryParams: new SearchAddress(street: 'Ocean Avenue'),
    jsonBody: new CreateAddress(street: 'Ocean Avenue', number: 42),
    formParams: new AuditFields(source: 'backoffice'),
);
  • queryParams maps to RequestOptions::QUERY
  • jsonBody maps to RequestOptions::JSON
  • formParams maps to RequestOptions::FORM_PARAMS

Pass null to omit an option. Empty arrays are treated as intentional payloads and are still passed to Guzzle.


Async

$address = $client
    ->getAsync(Address::class, '/addresses/aaa')
    ->wait();

The async methods return JacksonPromise, which decorates Guzzle's promise and maps fulfilled ResponseInterface values into your expected DTO.

$client
    ->postAsync(
        class: AddressCreated::class,
        uri: '/addresses',
        jsonBody: new CreateAddress(street: 'Ocean Avenue', number: 42),
    )
    ->then(fn(AddressCreated $created) => $created->id)
    ->wait();

Custom mappers

Pass php-jackson type mappers to the JacksonClient constructor when a type needs custom read or write behavior.

use GuzzleHttp\Client;
use Tcds\Io\Jackson\Guzzle\JacksonClient;

$client = new JacksonClient(
    guzzle: new Client([
        'base_uri' => 'https://api.example.com',
    ]),
    typeMappers: [
        User::class => [
            'reader' => fn(array $data) => new User(
                name: $data['name'],
                lastName: $data['surname'],
            ),
            'writer' => fn(User $user) => [
                'name' => $user->name,
                'surname' => $user->lastName,
            ],
        ],
    ],
);

Please refer to the core mapper documentation for additional configuration options.


Development

composer install
vendor/bin/phpunit --testdox

Related packages

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages