Catch API timeouts

This commit is contained in:
Timothy Warren 2017-04-05 13:01:51 -04:00
parent 8172d1a593
commit b861db5d1f
5 changed files with 159 additions and 51 deletions

View File

@ -54,7 +54,9 @@ class JsonAPI {
]; ];
// Reorganize included data // Reorganize included data
$included = static::organizeIncluded($data['included']); $included = (array_key_exists('included', $data))
? static::organizeIncluded($data['included'])
: [];
// Inline organized data // Inline organized data
foreach($data['data'] as $i => &$item) foreach($data['data'] as $i => &$item)
@ -138,10 +140,7 @@ class JsonAPI {
continue; continue;
} }
$relationship[$typeKey][$idKey] = array_merge( $relationship[$typeKey][$idKey][$j] = $included[$typeKey][$idKey];
$included[$typeKey][$idKey],
$relationship[$typeKey][$idKey] ?? []
);
} }
} }
} }
@ -149,6 +148,8 @@ class JsonAPI {
} }
} }
$data['data']['included'] = $included;
return $data['data']; return $data['data'];
} }
@ -202,11 +203,11 @@ class JsonAPI {
{ {
foreach($items as $id => $item) foreach($items as $id => $item)
{ {
if (array_key_exists('relationships', $item)) if (array_key_exists('relationships', $item) && is_array($item['relationships']))
{ {
foreach($item['relationships'] as $relType => $props) foreach($item['relationships'] as $relType => $props)
{ {
if (array_key_exists('data', $props)) if (array_key_exists('data', $props) && is_array($props['data']) && array_key_exists('id', $props['data']))
{ {
if (array_key_exists($props['data']['id'], $organized[$props['data']['type']])) if (array_key_exists($props['data']['id'], $organized[$props['data']['type']]))
{ {

View File

@ -22,7 +22,7 @@ use function Amp\wait;
use Amp\Artax\{Client, Request}; use Amp\Artax\{Client, Request};
use Aviat\AnimeClient\AnimeClient; use Aviat\AnimeClient\AnimeClient;
use Aviat\AnimeClient\API\Kitsu as K; use Aviat\AnimeClient\API\{FailedResponseException, Kitsu as K};
use Aviat\Ion\Json; use Aviat\Ion\Json;
trait KitsuTrait { trait KitsuTrait {
@ -142,8 +142,10 @@ trait KitsuTrait {
{ {
if ($logger) if ($logger)
{ {
$logger->warning('Non 200 response for api call', (array)$response->getBody()); $logger->warning('Non 200 response for api call', (array)$response);
} }
throw new FailedResponseException('Failed to get the proper response from the API');
} }
return Json::decode($response->getBody(), TRUE); return Json::decode($response->getBody(), TRUE);

View File

@ -160,13 +160,16 @@ class Model {
*/ */
public function getCharacter(string $slug): array public function getCharacter(string $slug): array
{ {
// @todo catch non-existent characters and show 404
$data = $this->getRequest('/characters', [ $data = $this->getRequest('/characters', [
'query' => [ 'query' => [
'filter' => [ 'filter' => [
'name' => $slug 'slug' => $slug,
], ],
// 'include' => 'primaryMedia,castings' 'fields' => [
'anime' => 'canonicalTitle,titles,slug,posterImage',
'manga' => 'canonicalTitle,titles,slug,posterImage'
],
'include' => 'castings.person,castings.media'
] ]
]); ]);

View File

@ -17,19 +17,23 @@
namespace Aviat\AnimeClient\Controller; namespace Aviat\AnimeClient\Controller;
use Aviat\AnimeClient\Controller as BaseController; use Aviat\AnimeClient\Controller as BaseController;
use Aviat\AnimeClient\API\JsonAPI;
use Aviat\Ion\ArrayWrapper;
/** /**
* Controller for character description pages * Controller for character description pages
*/ */
class Character extends BaseController { class Character extends BaseController {
use ArrayWrapper;
public function index(string $slug) public function index(string $slug)
{ {
$model = $this->container->get('kitsu-model'); $model = $this->container->get('kitsu-model');
$data = $model->getCharacter($slug); $rawData = $model->getCharacter($slug);
if (( ! array_key_exists('data', $data)) || empty($data['data'])) if (( ! array_key_exists('data', $rawData)) || empty($rawData['data']))
{ {
return $this->notFound( return $this->notFound(
$this->formatTitle( $this->formatTitle(
@ -40,12 +44,98 @@ class Character extends BaseController {
); );
} }
$this->outputHTML('character', [ $data = JsonAPI::organizeData($rawData);
$viewData = [
'title' => $this->formatTitle( 'title' => $this->formatTitle(
'Characters', 'Characters',
$data['data'][0]['attributes']['name'] $data[0]['attributes']['name']
), ),
'data' => $data['data'][0]['attributes'] 'data' => $data,
]); 'castings' => []
];
if (array_key_exists('included', $data) && array_key_exists('castings', $data['included']))
{
$viewData['castings'] = $this->organizeCast($data['included']['castings']);
}
$this->outputHTML('character', $viewData);
}
private function dedupeCast(array $cast): array
{
$output = [];
$people = [];
$i = 0;
foreach ($cast as &$role)
{
if (empty($role['attributes']['role']))
{
continue;
}
$person = current($role['relationships']['person']['people'])['attributes'];
if ( ! array_key_exists($person['name'], $people))
{
$people[$person['name']] = $i;
$role['relationships']['media']['anime'] = [current($role['relationships']['media']['anime'])];
$output[$i] = $role;
$i++;
continue;
}
else if(array_key_exists($person['name'], $people))
{
if (array_key_exists('anime', $role['relationships']['media']))
{
$key = $people[$person['name']];
$output[$key]['relationships']['media']['anime'][] = current($role['relationships']['media']['anime']);
}
continue;
}
}
return $output;
}
private function organizeCast(array $cast): array
{
$cast = $this->dedupeCast($cast);
$output = [];
foreach($cast as $id => $role)
{
if (empty($role['attributes']['role']))
{
continue;
}
$language = $role['attributes']['language'];
$roleName = $role['attributes']['role'];
$isVA = $role['attributes']['voiceActor'];
if ($isVA)
{
$person = current($role['relationships']['person']['people'])['attributes'];
$name = $person['name'];
$item = [
'person' => $person,
'series' => $role['relationships']['media']['anime']
];
$output[$roleName][$language][] = $item;
}
else
{
$output[$roleName][] = $role['relationships']['person']['people'];
}
}
return $output;
} }
} }

View File

@ -26,6 +26,7 @@ use const Aviat\AnimeClient\{
use function Aviat\Ion\_dir; use function Aviat\Ion\_dir;
use Aviat\AnimeClient\API\FailedResponseException;
use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Friend; use Aviat\Ion\Friend;
@ -256,14 +257,25 @@ class Dispatcher extends RoutingBase {
{ {
$logger = $this->container->getLogger('default'); $logger = $this->container->getLogger('default');
try
{
$controller = new $controllerName($this->container); $controller = new $controllerName($this->container);
// Run the appropriate controller method // Run the appropriate controller method
$logger->debug('Dispatcher - controller arguments'); $logger->debug('Dispatcher - controller arguments', $params);
$logger->debug(print_r($params, TRUE));
call_user_func_array([$controller, $method], $params); call_user_func_array([$controller, $method], $params);
} }
catch (FailedResponseException $e)
{
$controllerName = DEFAULT_CONTROLLER;
$controller = new $controllerName($this->container);
$controller->errorPage(500,
'API request timed out',
'Failed to retrieve data from API ☹️');
}
}
/** /**
* Get the appropriate params for the error page * Get the appropriate params for the error page