Skip to content

Instantly share code, notes, and snippets.

@zajca
Last active March 22, 2019 09:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zajca/626e4f8c1c9fd11864817cf283943460 to your computer and use it in GitHub Desktop.
Save zajca/626e4f8c1c9fd11864817cf283943460 to your computer and use it in GitHub Desktop.
NSP API Guzzle Client
eight_points_guzzle:
clients:
nsp:
class: App\Client\NSPApiClient
base_url: 'https://nsp.cz'
options:
timeout: 30
headers:
Accept: "application/json"
X-Accept-Version: "v1"
services:
_defaults:
autowire: true
autoconfigure: true
public: false
#guzzle
App\Client\NSPApiClient: '@eight_points_guzzle.client.nsp'
<?php
declare(strict_types=1);
// example fetch multiple
$requests = function () {
$uri = new Uri('/api/lists/healthCondition');
yield new Request('GET', $uri);
$uri = new Uri('/api/lists/qualificationRequirement');
yield new Request('GET', $uri);
};
$that = $this;
$this->NSPApiClient->fetchMultiple(
$requests, 5, function (Response $response, int $index) {
switch ($index) {
case 0:
// do something with first uri response
break;
case 1:
// do something with second uri response
break;
}
}, function (TransferException $reason, $index) {
throw new \Exception('Something is wrong request to nsp api index: '.$index);
}
);
// example fetch list
uri = new Uri('/api/professionalDirection');
$this->NSPApiClient->fetchList(
$uri, 10, function (Response $response, int $index) {
// do something with response
}, function (TransferException $reason, $index) {
throw new \Exception('Something is wrong request to nsp api index: '.$index.' failed');
}, ['level' => 1]
);
<?php
declare(strict_types=1);
namespace App\Base\Rest;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
trait JsonSerializerTrait
{
/**
* @var Serializer
*/
private $serializer;
public function getSerializer(): Serializer
{
if (null === $this->serializer) {
$this->serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
}
return $this->serializer;
}
public function decodeResponse(ResponseInterface $response): array
{
return $this->getSerializer()->decode((string) $response->getBody(), 'json');
}
}
<?php
declare(strict_types=1);
namespace App\Client;
use App\Base\Rest\JsonSerializerTrait;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Pool;
use function GuzzleHttp\Psr7\build_query;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\RequestOptions;
class NSPApiClient extends Client
{
use JsonSerializerTrait;
private const DEFAULT_QUERY = [
'offset' => 0,
'limit' => 0,
];
private const DEFAULT_LIMIT = 100;
public function __construct(array $config = [])
{
parent::__construct($config);
/** @var HandlerStack $handler */
$handler = $this->getConfig('handler');
$handler->push(Middleware::retry($this->retryDecider(), $this->retryDelay()), 'retry');
}
/**
* Check number of retries of request
*/
private function retryDecider(): callable
{
return function (
$retries,
Request $request,
Response $response = null,
RequestException $exception = null
) {
// Limit the number of retries to 5
if ($retries >= 10) {
return false;
}
// Retry connection exceptions
if ($exception instanceof ConnectException) {
return true;
}
if ($response && $response->getStatusCode() >= 500) {
return true;
}
return false;
};
}
/**
* delay 1s 2s 3s 4s 5s.
*
* @return \Closure
*/
private function retryDelay(): callable
{
return function ($numberOfRetries) {
return 1000 * $numberOfRetries;
};
}
/**
* fetch multiple url at once
*/
public function fetchMultiple(callable $requests, int $batchSize, callable $cbFulfilled, callable $cbRejected): void
{
$pool = new Pool(
$this, $requests(), [
'concurrency' => $batchSize,
'fulfilled' => $cbFulfilled,
'rejected' => $cbRejected,
'options' => [
RequestOptions::EXPECT => false,
RequestOptions::VERSION => 1.0,
],
]
);
$promise = $pool->promise();
$promise->wait();
}
/**
* Fetch nsp whole list
*/
public function fetchList(Uri $uri, int $batchSize, callable $cbFulfilled, callable $cbRejected, array $query): void
{
$totalCount = 0;
// first request is to check number of pages
$promise = $this->sendAsync(
new Request('GET', $uri->withQuery(build_query(\array_merge(self::DEFAULT_QUERY, $query))))
)->then(
function (Response $response) use (&$totalCount) {
$data = $this->decodeResponse($response);
$totalCount = $data['count'];
}
)
;
$promise->wait();
$limit = self::DEFAULT_LIMIT;
$requests = function () use ($uri, $totalCount, $limit, $query) {
$totalRequests = 0;
for ($i = 0; $i < $totalCount; $i += $limit) {
++$totalRequests;
$req = new Request(
'GET', $uri->withQuery(
build_query(
\array_merge(
[
'offset' => $i,
'limit' => $limit,
], $query
)
)
)
);
yield $req;
}
echo 'Total requests: '.$totalRequests;
};
$pool = new Pool(
$this, $requests(), [
'concurrency' => $batchSize,
'fulfilled' => $cbFulfilled,
'rejected' => $cbRejected,
'options' => [
RequestOptions::EXPECT => false,
RequestOptions::VERSION => 1.0,
],
]
);
$promise = $pool->promise();
$promise->wait();
}
/**
* fetch single json url
*/
public function fetchUrl(string $url): array
{
$response = $this->get($url);
return $this->decodeResponse($response);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment