Last active
March 22, 2019 09:04
-
-
Save zajca/626e4f8c1c9fd11864817cf283943460 to your computer and use it in GitHub Desktop.
NSP API Guzzle Client
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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] | |
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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