PHP code example of deeep / service-client-bundle

1. Go to this page and download the library: Download deeep/service-client-bundle library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

deeep / service-client-bundle example snippets


return [
    // ...
    Deeep\ServiceClient\ServiceClientBundle::class => ['all' => true],
];


// config/packages/deeep_service_client.php

declare(strict_types=1);

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

return App::config([
    'deeep_service_client' => [
        'defaults' => [
            'timeout' => [
                'connect' => 5.0,
                'request' => 30.0,
            ],
            'retry' => [
                'enabled' => true,
                'max_attempts' => 3,
                'delay' => 1000,
                'multiplier' => 2.0,
                'jitter' => 0.1,
            ],
        ],

        'services' => [
            'my_api' => [
                'host' => '%env(resolve:MY_API_HOST)%',
                'auth' => [
                    'type' => 'bearer',
                    'credentials' => [
                        'token' => '%env(resolve:MY_API_TOKEN)%',
                    ],
                ],
            ],

            'resilient_api' => [
                'hosts' => [
                    'strategy' => 'failover',
                    'list' => [
                        ['url' => '%env(resolve:API_PRIMARY)%'],
                        ['url' => '%env(resolve:API_BACKUP)%'],
                    ],
                ],
            ],
        ],
    ],
]);

use Deeep\ServiceClient\Contract\AuthRequiredInterface;
use Deeep\ServiceClient\Contract\MappableRequestInterface;
use Deeep\ServiceClient\Contract\ResponseInterface;
use Deeep\ServiceClient\Enum\HttpMethod;
use Deeep\ServiceClient\Request\AbstractRequest;

/**
 * @implements MappableRequestInterface<User>
 */
final readonly class GetUserRequest extends AbstractRequest implements
    AuthRequiredInterface,
    MappableRequestInterface
{
    public function __construct(
        private int $userId,
    ) {}

    public function getService(): string
    {
        return 'my_api';
    }

    public function getMethod(): HttpMethod
    {
        return HttpMethod::GET;
    }

    public function getUri(): string
    {
        return "/users/{$this->userId}";
    }

    /**
     * @param ResponseInterface<mixed> $response
     */
    public function mapResponse(ResponseInterface $response): User
    {
        $data = $response->toArray();

        return new User($data['id'], $data['name'], $data['email']);
    }
}

// Usage
$request = new GetUserRequest(123);
$response = $httpClient->send($request);
$user = $response->getData(); // User

use Deeep\ServiceClient\Contract\AuthRequiredInterface;
use Deeep\ServiceClient\Contract\MappableRequestInterface;
use Deeep\ServiceClient\Contract\ResponseInterface;
use Deeep\ServiceClient\Enum\HttpMethod;
use Deeep\ServiceClient\Request\AbstractRequest;

/**
 * @implements MappableRequestInterface<User>
 */
final readonly class CreateUserRequest extends AbstractRequest implements
    AuthRequiredInterface,
    MappableRequestInterface
{
    public function __construct(
        private string $name,
        private string $email,
    ) {}

    public function getService(): string
    {
        return 'my_api';
    }

    public function getMethod(): HttpMethod
    {
        return HttpMethod::POST;
    }

    public function getUri(): string
    {
        return '/users';
    }

    /**
     * @return array{name: string, email: string}
     */
    public function getBody(): array
    {
        return [
            'name' => $this->name,
            'email' => $this->email,
        ];
    }

    /**
     * @param ResponseInterface<mixed> $response
     */
    public function mapResponse(ResponseInterface $response): User
    {
        $data = $response->toArray();

        return new User($data['id'], $data['name'], $data['email']);
    }
}

$request = $requestBuilder
    ->service('my_api')
    ->get('/users')
    ->query(['limit' => 10])
    ->build();

$response = $httpClient->send($request);
$users = $response->toArray();

$base = $requestBuilder->service('api')->header('X-Tenant', 'acme');
$request1 = $base->get('/users')->build();
$request2 = $base->get('/orders')->build();  // Both have X-Tenant header

// Launch multiple requests
$results = [];
foreach ($userIds as $id) {
    $results[$id] = $httpClient->sendAsync(new GetUserRequest($id));
}

// Await all
$responses = $httpClient->await(...$results);

foreach ($responses as $id => $response) {
    $users[$id] = $response->getData();
}

$httpClient->sendAsync(
    $request,
    onResponse: fn($response) => $this->process($response),
    onError: fn($e) => $this->logger->error($e->getMessage()),
);

$result = $httpClient->sendAsync($request);

$result
    ->then(fn($response) => $this->handleSuccess($response))
    ->onErrorResponse(fn($response) => $this->handleApiError($response))
    ->then(null, fn($e) => $this->handleNetworkError($e));

$response = $result->await();

use Deeep\ServiceClient\Contract\ErrorMappableRequestInterface;
use Deeep\ServiceClient\Contract\MappableRequestInterface;
use Deeep\ServiceClient\Contract\ResponseInterface;
use Deeep\ServiceClient\Request\AbstractRequest;

/**
 * @implements MappableRequestInterface<User>
 * @implements ErrorMappableRequestInterface<ApiError>
 */
final readonly class GetUserRequest extends AbstractRequest implements
    MappableRequestInterface,
    ErrorMappableRequestInterface
{
    // ... getService(), getMethod(), getUri()

    /**
     * @param ResponseInterface<mixed> $response
     */
    public function mapResponse(ResponseInterface $response): User
    {
        $data = $response->toArray();

        return new User($data['id'], $data['name'], $data['email']);
    }

    /**
     * @param ResponseInterface<mixed> $response
     */
    public function mapErrorResponse(ResponseInterface $response): ApiError
    {
        $data = $response->toArray();

        return new ApiError($data['code'], $data['message']);
    }
}

'services' => [
    'api' => [
        'hosts' => [
            'strategy' => 'failover',
            'list' => [
                ['url' => 'https://primary.example.com'],
                ['url' => 'https://backup.example.com'],
            ],
        ],
    ],
],

'services' => [
    'api' => [
        'hosts' => [
            'strategy' => 'round_robin',
            'list' => [
                ['url' => 'https://node1.example.com'],
                ['url' => 'https://node2.example.com'],
                ['url' => 'https://node3.example.com'],
            ],
        ],
    ],
],

'services' => [
    'api' => [
        'hosts' => [
            'strategy' => 'parallel',
            'list' => [
                ['url' => 'https://fast.example.com'],
                ['url' => 'https://slow.example.com'],
            ],
        ],
    ],
],

'defaults' => [
    'retry' => [
        'enabled' => true,
        'max_attempts' => 3,           // Total attempts (1 initial + 2 retries)
        'delay' => 1000,               // Initial delay in ms
        'multiplier' => 2.0,           // Exponential multiplier
        'max_delay' => 30000,          // Maximum delay in ms
        'jitter' => 0.1,               // Random jitter (0-1)
        'retry_on' => [429, 502, 503, 504],
        'retry_on_methods' => ['GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS'],
        'respect_retry_after' => true,
    ],
],

'services' => [
    'api' => [
        'host' => '%env(resolve:API_HOST)%',
        'auth' => [
            'type' => 'bearer',
            'credentials' => [
                'token' => '%env(resolve:API_TOKEN)%',
            ],
        ],
    ],
],

'services' => [
    'api' => [
        'host' => '%env(resolve:API_HOST)%',
        'auth' => [
            'type' => 'api_key',
            'credentials' => [
                'header' => 'X-Api-Key',  // Default: Api-Key
                'token' => '%env(resolve:API_KEY)%',
            ],
        ],
    ],
],

'services' => [
    'api' => [
        'host' => '%env(resolve:API_HOST)%',
        'auth' => [
            'type' => 'basic',
            'credentials' => [
                'username' => '%env(resolve:API_USER)%',
                'password' => '%env(resolve:API_PASS)%',
            ],
        ],
    ],
],