Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/error handling #3

Merged
merged 2 commits into from
Oct 4, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"prefer-stable": true,
"require": {
"php": "^7",
"amphp/artax": "^2"
"amphp/artax": "^2",
"daverandom/exceptional-json": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^5"
Expand Down
49 changes: 42 additions & 7 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Api/BadGatewayException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php declare(strict_types = 1);

namespace PeeHaa\AsyncTwitter\Api;

class BadGatewayException extends ServerErrorException {}
5 changes: 5 additions & 0 deletions src/Api/BadRequestException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php declare(strict_types = 1);

namespace PeeHaa\AsyncTwitter\Api;

class BadRequestException extends ClientErrorException {}
67 changes: 65 additions & 2 deletions src/Api/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace PeeHaa\AsyncTwitter\Api;

use Amp\Artax\Response as HttpResponse;
use Amp\Promise;
use ExceptionalJSON\DecodeErrorException as JSONDecodeErrorException;
use PeeHaa\AsyncTwitter\Credentials\AccessToken;
use PeeHaa\AsyncTwitter\Credentials\Application;
use PeeHaa\AsyncTwitter\Http\Artax;
Expand All @@ -14,6 +16,8 @@
use PeeHaa\AsyncTwitter\Request\Body;
use PeeHaa\AsyncTwitter\Request\Parameter;
use PeeHaa\AsyncTwitter\Request\Url;
use function Amp\resolve;
use function ExceptionalJSON\decode as json_try_decode;

class Client
{
Expand Down Expand Up @@ -44,18 +48,77 @@ public function request(Request $request): Promise
}
}

private function getErrorStringFromResponseBody(array $body)
{
if (!isset($body['errors'])) {
return ['Unknown error', -1, []];
}

$message = (string)($body['errors'][0]['message'] ?? 'Unknown error');
$code = (int)($body['errors'][0]['code'] ?? -1);
$extra = [];

for ($i = 1; isset($body['errors'][$i]); $i++) {
$extra[(int)($body['errors'][$i]['code'] ?? -1)] = (string)($body['errors'][$i]['message'] ?? 'Unknown error');
}

return [$message, $code, $extra];
}

// https://dev.twitter.com/overview/api/response-codes
private function throwFromErrorResponse(HttpResponse $response, array $body)
{
list($message, $code, $extra) = $this->getErrorStringFromResponseBody($body);

switch ($response->getStatus()) {
case 400: throw new BadRequestException($message, $code, null, $extra);
case 401: throw new UnauthorizedException($message, $code, null, $extra);
case 403: throw new ForbiddenException($message, $code, null, $extra);
case 404: throw new NotFoundException($message, $code, null, $extra);
case 406: throw new NotAcceptableException($message, $code, null, $extra);
case 410: throw new GoneException($message, $code, null, $extra);
case 420: throw new RateLimitTriggeredException($message, $code, null, $extra);
case 422: throw new UnprocessableEntityException($message, $code, null, $extra);
case 429: throw new RateLimitTriggeredException($message, $code, null, $extra);
case 500: throw new ServerErrorException($message, $code, null, $extra);
case 502: throw new BadGatewayException($message, $code, null, $extra);
case 503: throw new ServiceUnavailableException($message, $code, null, $extra);
case 504: throw new GatewayTimeoutException($message, $code, null, $extra);
}
}

private function handleResponse(Promise $responsePromise): Promise
{
return resolve(function() use($responsePromise) {
/** @var HttpResponse $response */
$response = yield $responsePromise;

try {
$decoded = json_try_decode($response->getBody(), true);
} catch (JSONDecodeErrorException $e) {
throw new RequestFailedException('Failed to decode response body as JSON', $e->getCode(), $e);
}

$this->throwFromErrorResponse($response, $decoded);

return $decoded;
});
}

private function post(Request $request): Promise
{
$header = $this->getHeader('POST', $request->getEndpoint(), ...$request->getParameters());

return $this->httpClient->post($request->getEndpoint(), $header, new Body(...$request->getParameters()));
$response = $this->httpClient->post($request->getEndpoint(), $header, new Body(...$request->getParameters()));
return $this->handleResponse($response);
}

private function get(Request $request): Promise
{
$header = $this->getHeader('GET', $request->getEndpoint(), ...$request->getParameters());

return $this->httpClient->get($request->getEndpoint(), $header, ...$request->getParameters());
$response = $this->httpClient->get($request->getEndpoint(), $header, ...$request->getParameters());
return $this->handleResponse($response);
}

private function getHeader(string $method, Url $url, Parameter ...$parameters): Header
Expand Down
5 changes: 5 additions & 0 deletions src/Api/ClientErrorException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php declare(strict_types = 1);

namespace PeeHaa\AsyncTwitter\Api;

class ClientErrorException extends RequestFailedException {}
5 changes: 5 additions & 0 deletions src/Api/ForbiddenException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php declare(strict_types = 1);

namespace PeeHaa\AsyncTwitter\Api;

class ForbiddenException extends ClientErrorException {}
5 changes: 5 additions & 0 deletions src/Api/GatewayTimeoutException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php declare(strict_types = 1);

namespace PeeHaa\AsyncTwitter\Api;

class GatewayTimeoutException extends ServerErrorException {}
5 changes: 5 additions & 0 deletions src/Api/GoneException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php declare(strict_types = 1);

namespace PeeHaa\AsyncTwitter\Api;

class GoneException extends ClientErrorException {}
5 changes: 5 additions & 0 deletions src/Api/NotAcceptableException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php declare(strict_types = 1);

namespace PeeHaa\AsyncTwitter\Api;

class NotAcceptableException extends ClientErrorException {}
5 changes: 5 additions & 0 deletions src/Api/NotFoundException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php declare(strict_types = 1);

namespace PeeHaa\AsyncTwitter\Api;

class NotFoundException extends ClientErrorException {}
5 changes: 5 additions & 0 deletions src/Api/RateLimitTriggeredException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php declare(strict_types = 1);

namespace PeeHaa\AsyncTwitter\Api;

class RateLimitTriggeredException extends ClientErrorException {}
27 changes: 27 additions & 0 deletions src/Api/RequestFailedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php declare(strict_types = 1);

namespace PeeHaa\AsyncTwitter\Api;

use PeeHaa\AsyncTwitter\Exception;

class RequestFailedException extends Exception
{
private $extraErrorInfo;

public function __construct(string $message, int $code = 0, \Throwable $previous = null, array $extraErrorInfo = [])
{
parent::__construct($message, $code, $previous);

$this->extraErrorInfo = $extraErrorInfo;
}

public function hasExtraErrorInfo(): bool
{
return (bool)count($this->extraErrorInfo);
}

public function getExtraErrorInfo(): array
{
return $this->extraErrorInfo;
}
}
5 changes: 5 additions & 0 deletions src/Api/ServerErrorException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php declare(strict_types = 1);

namespace PeeHaa\AsyncTwitter\Api;

class ServerErrorException extends RequestFailedException {}
5 changes: 5 additions & 0 deletions src/Api/ServiceUnavailableException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php declare(strict_types = 1);

namespace PeeHaa\AsyncTwitter\Api;

class ServiceUnavailableException extends ServerErrorException {}
5 changes: 5 additions & 0 deletions src/Api/UnauthorizedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php declare(strict_types = 1);

namespace PeeHaa\AsyncTwitter\Api;

class UnauthorizedException extends ClientErrorException {}
5 changes: 5 additions & 0 deletions src/Api/UnprocessableEntityException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php declare(strict_types = 1);

namespace PeeHaa\AsyncTwitter\Api;

class UnprocessableEntityException extends ClientErrorException {}