mirakl / sdk-php-shop

Mirakl PHP SDK for sellers
30 stars 16 forks source link

implement possibility to manipulate Guzzle Client stack in \Mirakl\Core\Client\AbstractApiClient::getDefaultClient #59

Closed jszczypk closed 6 months ago

jszczypk commented 10 months ago

Hi,

With deprecation and possible removal of \GuzzleHttp\Client::getConfig it will become impossible to manipulate HandlerStack of Guzzle client after it has been created. https://github.com/guzzle/guzzle/issues/2514

My use case is adding additional handler to HandlerStack in custom ShopApiClient to have it to retry request when hitting API limits.

class ShopApiClient extends \Mirakl\MMP\Shop\Client\ShopApiClient {

  const API_URL = 'https://marketplace.home-you.com/api';

  public function __construct(string $apiKey, ?string $shopId = NULL) {
    parent::__construct(self::API_URL, $apiKey, $shopId);

    $stack = $this->getClient()->getConfig('handler');

    $maxRetries = 10;

    $decider = function(int $retries, \Psr\Http\Message\RequestInterface $request, \Psr\Http\Message\ResponseInterface $response = null) use ($maxRetries) : bool {
      return 
        $retries < $maxRetries
        && null !== $response 
        && 429 === $response->getStatusCode();
    };

    $delay = function(int $retries, \Psr\Http\Message\ResponseInterface $response) : int {

      if (!$response->hasHeader('Retry-After')) {
        return \GuzzleHttp\RetryMiddleware::exponentialDelay($retries);
      }

      $retryAfter = $response->getHeaderLine('Retry-After');

      if (!is_numeric($retryAfter)) {
        $retryAfter = (new \DateTime($retryAfter))->getTimestamp() - time();
      }

      return (int) $retryAfter * 1000;
    };

    $stack->push(\GuzzleHttp\Middleware::retry($decider, $delay));

  }

}

In \Mirakl\Core\Client\AbstractApiClient stack is hardcoded and it is not possible to extend getDefaultClient.

My suggestion is to add function getDefaultClientParams that will provide parameter to \GuzzleHttp\Client constructor.


    /**
     * @return  array
     */
    protected function getDefaultClientParams()
    {
        $stack = GuzzleHttp\HandlerStack::create();
        $stack->push(GuzzleHttp\Middleware::history($this->history));

        $logger = $this->getLogger();
        if (!empty($logger)) {
            $stack->push(GuzzleHttp\Middleware::log($logger, $this->getMessageFormatter()));
        }

        return [
            'handler' => $stack,
            'base_uri' => rtrim($this->getBaseUrl(), '/') . '/',
            'headers' => [
                'User-Agent' => $this->getUserAgent() ?: static::getDefaultUserAgent(),
                'Authorization' => $this->getApiKey(),
                'Accept' => 'application/json',
            ],
        ];
    }

    /**
     * @return  GuzzleHttp\Client
     */
    protected function getDefaultClient()
    {
        return new GuzzleHttp\Client($this->getDefaultClientParams());
    }

Best regards, Janusz

mhnkhalifa commented 9 months ago

Hi @jszczypk , I created an internal ticket and we will take this into account when preparing the next release of the Magento 2 seller PHP SDK. Thank you for your feedback.