Catch API timeouts

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

View File

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

View File

@ -22,7 +22,7 @@ use function Amp\wait;
use Amp\Artax\{Client, Request};
use Aviat\AnimeClient\AnimeClient;
use Aviat\AnimeClient\API\Kitsu as K;
use Aviat\AnimeClient\API\{FailedResponseException, Kitsu as K};
use Aviat\Ion\Json;
trait KitsuTrait {
@ -142,8 +142,10 @@ trait KitsuTrait {
{
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);

View File

@ -160,13 +160,16 @@ class Model {
*/
public function getCharacter(string $slug): array
{
// @todo catch non-existent characters and show 404
$data = $this->getRequest('/characters', [
'query' => [
'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;
use Aviat\AnimeClient\Controller as BaseController;
use Aviat\AnimeClient\API\JsonAPI;
use Aviat\Ion\ArrayWrapper;
/**
* Controller for character description pages
*/
class Character extends BaseController {
use ArrayWrapper;
public function index(string $slug)
{
$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(
$this->formatTitle(
@ -40,12 +44,98 @@ class Character extends BaseController {
);
}
$this->outputHTML('character', [
$data = JsonAPI::organizeData($rawData);
$viewData = [
'title' => $this->formatTitle(
'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 Aviat\AnimeClient\API\FailedResponseException;
use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Friend;
@ -256,14 +257,25 @@ class Dispatcher extends RoutingBase {
{
$logger = $this->container->getLogger('default');
try
{
$controller = new $controllerName($this->container);
// Run the appropriate controller method
$logger->debug('Dispatcher - controller arguments');
$logger->debug(print_r($params, TRUE));
$logger->debug('Dispatcher - controller arguments', $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