feat(service): add api service
This commit is contained in:
@@ -7,8 +7,8 @@ namespace App\Entity\Remote\Brilo\Users;
|
||||
readonly class AddressGeo
|
||||
{
|
||||
public function __construct(
|
||||
public float $lat,
|
||||
public float $lng,
|
||||
public string $lat,
|
||||
public string $lng,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
35
src/Service/Remote/BriloApiComments.php
Normal file
35
src/Service/Remote/BriloApiComments.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Remote;
|
||||
|
||||
use App\Entity\Remote\Brilo\Comments\Comment;
|
||||
use App\Entity\Remote\Brilo\Posts\Post;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
class BriloApiComments
|
||||
{
|
||||
use BriloApiFetchTrait;
|
||||
|
||||
public function __construct(
|
||||
protected readonly HttpClientInterface $httpClient,
|
||||
protected readonly LoggerInterface $logger,
|
||||
protected readonly SerializerInterface $serializer,
|
||||
protected readonly int $retryCount = 3,
|
||||
protected readonly int $sleepTimeS = 1,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all comments from the Brilo API and return them as an array of Comment entities.
|
||||
* @return Comment[]
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getComments(): array
|
||||
{
|
||||
return $this->fetchApiResponse('https://jsonplaceholder.typicode.com/comments', Comment::class);
|
||||
}
|
||||
}
|
||||
54
src/Service/Remote/BriloApiFetchTrait.php
Normal file
54
src/Service/Remote/BriloApiFetchTrait.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Remote;
|
||||
|
||||
use App\Entity\Remote\Brilo\Users\User;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpClient\Exception\TransportException;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
trait BriloApiFetchTrait
|
||||
{
|
||||
use RetryingClientTrait;
|
||||
|
||||
protected readonly int $retryCount;
|
||||
protected readonly int $sleepTimeS;
|
||||
protected readonly LoggerInterface $logger;
|
||||
protected readonly HttpClientInterface $httpClient;
|
||||
protected readonly SerializerInterface $serializer;
|
||||
|
||||
/**
|
||||
* Implementation of fetch logic. Handles retrying and logging of failed requests.
|
||||
* Returns deserialized data.
|
||||
* @template T
|
||||
*
|
||||
* @param string $uri Uri of the API endpoint.
|
||||
* @param class-string<T> $class Class name of the entity to deserialize data into.
|
||||
*
|
||||
* @return T[]
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function fetchApiResponse(string $uri, string $class): array
|
||||
{
|
||||
return $this->retryingFailRequest($this->retryCount, $this->sleepTimeS, [TransportException::class, BriloRemoteApiException::class], $this->logger, function () use ($uri, $class) {
|
||||
$this->logger->debug('Trying to download brilo users');
|
||||
|
||||
$response = $this->httpClient->request('GET', $uri);
|
||||
|
||||
if ($response->getStatusCode() != 200) {
|
||||
$this->logger->error("Can't download brilo users. HTTP status code: " . $response->getStatusCode());
|
||||
throw new BriloRemoteApiException("Can't download brilo users. HTTP status code: " . $response->getStatusCode());
|
||||
}
|
||||
|
||||
$this->logger->debug('Brilo users downloaded');
|
||||
|
||||
$this->logger->debug('Deserialize brilo users');
|
||||
|
||||
// extra attributes muzeme safe ignorovat
|
||||
return $this->serializer->deserialize($response->getContent(), $class . '[]', 'json');
|
||||
});
|
||||
}
|
||||
}
|
||||
10
src/Service/Remote/BriloApiPosts.php
Normal file
10
src/Service/Remote/BriloApiPosts.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Remote;
|
||||
|
||||
class BriloApiPosts
|
||||
{
|
||||
|
||||
}
|
||||
35
src/Service/Remote/BriloApiUsers.php
Normal file
35
src/Service/Remote/BriloApiUsers.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Remote;
|
||||
|
||||
use App\Entity\Remote\Brilo\Users\User;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpClient\Exception\TransportException;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
final class BriloApiUsers
|
||||
{
|
||||
use BriloApiFetchTrait;
|
||||
|
||||
public function __construct(
|
||||
protected readonly HttpClientInterface $httpClient,
|
||||
protected readonly LoggerInterface $logger,
|
||||
protected readonly SerializerInterface $serializer,
|
||||
protected readonly int $retryCount = 3,
|
||||
protected readonly int $sleepTimeS = 1,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User[]
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getUsers(): array
|
||||
{
|
||||
return $this->fetchApiResponse('https://jsonplaceholder.typicode.com/users', User::class);
|
||||
}
|
||||
}
|
||||
12
src/Service/Remote/BriloRemoteApiException.php
Normal file
12
src/Service/Remote/BriloRemoteApiException.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Remote;
|
||||
|
||||
/**
|
||||
* Remote API exception (in case return code from API endpoint is not 200 - OK)
|
||||
*/
|
||||
class BriloRemoteApiException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
58
src/Service/Remote/RetryingClientTrait.php
Normal file
58
src/Service/Remote/RetryingClientTrait.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Remote;
|
||||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
trait RetryingClientTrait
|
||||
{
|
||||
/**
|
||||
* Better to retry failed requests (in case of non-destructive operations) than throwing immediately.
|
||||
*
|
||||
* @param int $count
|
||||
* @param float $sleep
|
||||
* @param array<string> $catchableExceptions
|
||||
* @param LoggerInterface $logger
|
||||
* @param callable $callback
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function retryingFailRequest(
|
||||
int $count,
|
||||
float $sleep,
|
||||
array $catchableExceptions,
|
||||
LoggerInterface $logger,
|
||||
callable $callback
|
||||
): mixed {
|
||||
for ($i = 0;; $i++) {
|
||||
try {
|
||||
return $callback();
|
||||
} catch (Exception $e) {
|
||||
foreach ($catchableExceptions as $exceptionClass) {
|
||||
if ($e instanceof $exceptionClass) {
|
||||
$logger->error("transport: fail request retrying... got catchable exception", [
|
||||
'exception' => $e,
|
||||
'try' => $i
|
||||
]);
|
||||
|
||||
usleep((int) ($sleep * 1_000_000));
|
||||
|
||||
if ($i == $count) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
// phpstan fail
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user