Improving safe hydrate (#307)

* Improving safe deseriliaze

* Fixes

* Use switch statement

* cs

* bugfix

* Update method name

* Update return docs
This commit is contained in:
Tobias Nyholm 2017-03-26 10:16:36 +02:00 committed by GitHub
parent e74d7ad130
commit 0f4fe2bf9c
22 changed files with 159 additions and 95 deletions

View File

@ -49,7 +49,7 @@ class Domain extends HttpApi
$response = $this->httpGet('/v3/domains', $params);
return $this->safeHydrate($response, IndexResponse::class);
return $this->hydrateResponse($response, IndexResponse::class);
}
/**
@ -65,7 +65,7 @@ class Domain extends HttpApi
$response = $this->httpGet(sprintf('/v3/domains/%s', $domain));
return $this->safeHydrate($response, ShowResponse::class);
return $this->hydrateResponse($response, ShowResponse::class);
}
/**
@ -97,7 +97,7 @@ class Domain extends HttpApi
$response = $this->httpPost('/v3/domains', $params);
return $this->safeHydrate($response, CreateResponse::class);
return $this->hydrateResponse($response, CreateResponse::class);
}
/**
@ -114,7 +114,7 @@ class Domain extends HttpApi
$response = $this->httpDelete(sprintf('/v3/domains/%s', $domain));
return $this->safeHydrate($response, DeleteResponse::class);
return $this->hydrateResponse($response, DeleteResponse::class);
}
/**
@ -139,7 +139,7 @@ class Domain extends HttpApi
$response = $this->httpGet(sprintf('/v3/domains/%s/credentials', $domain), $params);
return $this->safeHydrate($response, CredentialResponse::class);
return $this->hydrateResponse($response, CredentialResponse::class);
}
/**
@ -165,7 +165,7 @@ class Domain extends HttpApi
$response = $this->httpPost(sprintf('/v3/domains/%s/credentials', $domain), $params);
return $this->safeHydrate($response, CreateCredentialResponse::class);
return $this->hydrateResponse($response, CreateCredentialResponse::class);
}
/**
@ -190,7 +190,7 @@ class Domain extends HttpApi
$response = $this->httpPut(sprintf('/v3/domains/%s/credentials/%s', $domain, $login), $params);
return $this->safeHydrate($response, UpdateCredentialResponse::class);
return $this->hydrateResponse($response, UpdateCredentialResponse::class);
}
/**
@ -214,7 +214,7 @@ class Domain extends HttpApi
)
);
return $this->safeHydrate($response, DeleteCredentialResponse::class);
return $this->hydrateResponse($response, DeleteCredentialResponse::class);
}
/**
@ -222,7 +222,7 @@ class Domain extends HttpApi
*
* @param string $domain Name of the domain.
*
* @return ConnectionResponse|array|ResponseInterface
* @return ConnectionResponse|ResponseInterface
*/
public function connection($domain)
{
@ -230,7 +230,7 @@ class Domain extends HttpApi
$response = $this->httpGet(sprintf('/v3/domains/%s/connection', $domain));
return $this->safeHydrate($response, ConnectionResponse::class);
return $this->hydrateResponse($response, ConnectionResponse::class);
}
/**
@ -261,6 +261,6 @@ class Domain extends HttpApi
$response = $this->httpPut(sprintf('/v3/domains/%s/connection', $domain), $params);
return $this->safeHydrate($response, UpdateConnectionResponse::class);
return $this->hydrateResponse($response, UpdateConnectionResponse::class);
}
}

View File

@ -33,7 +33,7 @@ class Event extends HttpApi
$response = $this->httpGet(sprintf('/v3/%s/events', $domain), $params);
return $this->safeHydrate($response, EventResponse::class);
return $this->hydrateResponse($response, EventResponse::class);
}
/**

View File

@ -11,12 +11,12 @@ namespace Mailgun\Api;
use Http\Client\Exception as HttplugException;
use Http\Client\HttpClient;
use Mailgun\Exception\UnknownErrorException;
use Mailgun\Hydrator\Hydrator;
use Mailgun\Hydrator\NoopHydrator;
use Mailgun\Exception\HttpClientException;
use Mailgun\Exception\HttpServerException;
use Mailgun\RequestBuilder;
use Mailgun\Model\ErrorResponse;
use Psr\Http\Message\ResponseInterface;
/**
@ -56,38 +56,58 @@ abstract class HttpApi
}
/**
* Attempts to safely deserialize the response into the given class.
* If the HTTP return code != 200, deserializes into SimpleResponse::class
* to contain the error message and any other information provided.
*
* @param ResponseInterface $response
* @param string $className
* @param string $class
*
* @throws HttpClientException
* @return mixed|ResponseInterface
*
* @return object $class
* @throws \Exception
*/
protected function safeHydrate(ResponseInterface $response, $className)
protected function hydrateResponse(ResponseInterface $response, $class)
{
if (!$this->hydrator) {
return $response;
}
if ($response->getStatusCode() === 200) {
return $this->hydrator->deserialize($response, $className);
} elseif ($response->getStatusCode() === 401) {
throw HttpClientException::unauthorized();
} else {
return $this->hydrator->deserialize($response, ErrorResponse::class);
if ($response->getStatusCode() !== 200 && $response->getStatusCode() !== 201) {
$this->handleErrors($response);
}
return $this->hydrator->hydrate($response, $class);
}
/**
* Throw the correct exception for this error.
*
* @param ResponseInterface $response
*
* @throws \Exception
*/
protected function handleErrors(ResponseInterface $response)
{
$statusCode = $response->getStatusCode();
switch ($statusCode) {
case 400:
throw HttpClientException::badRequest($response);
case 401:
throw HttpClientException::unauthorized($response);
case 402:
throw HttpClientException::requestFailed($response);
case 404:
throw HttpClientException::notFound($response);
case 500 <= $statusCode:
throw HttpServerException::serverError($statusCode);
default:
throw new UnknownErrorException();
}
}
/**
* Send a GET request with query parameters.
*
* @param string $path Request path.
* @param array $parameters GET parameters.
* @param array $requestHeaders Request Headers.
* @param string $path Request path
* @param array $parameters GET parameters
* @param array $requestHeaders Request Headers
*
* @return ResponseInterface
*/
@ -111,9 +131,9 @@ abstract class HttpApi
/**
* Send a POST request with JSON-encoded parameters.
*
* @param string $path Request path.
* @param array $parameters POST parameters to be JSON encoded.
* @param array $requestHeaders Request headers.
* @param string $path Request path
* @param array $parameters POST parameters to be JSON encoded
* @param array $requestHeaders Request headers
*
* @return ResponseInterface
*/
@ -125,9 +145,9 @@ abstract class HttpApi
/**
* Send a POST request with raw data.
*
* @param string $path Request path.
* @param array|string $body Request body.
* @param array $requestHeaders Request headers.
* @param string $path Request path
* @param array|string $body Request body
* @param array $requestHeaders Request headers
*
* @return ResponseInterface
*/
@ -147,9 +167,9 @@ abstract class HttpApi
/**
* Send a PUT request with JSON-encoded parameters.
*
* @param string $path Request path.
* @param array $parameters POST parameters to be JSON encoded.
* @param array $requestHeaders Request headers.
* @param string $path Request path
* @param array $parameters POST parameters to be JSON encoded
* @param array $requestHeaders Request headers
*
* @return ResponseInterface
*/
@ -169,9 +189,9 @@ abstract class HttpApi
/**
* Send a DELETE request with JSON-encoded parameters.
*
* @param string $path Request path.
* @param array $parameters POST parameters to be JSON encoded.
* @param array $requestHeaders Request headers.
* @param string $path Request path
* @param array $parameters POST parameters to be JSON encoded
* @param array $requestHeaders Request headers
*
* @return ResponseInterface
*/

View File

@ -68,7 +68,7 @@ class Message extends HttpApi
$response = $this->httpPostRaw(sprintf('/v3/%s/messages', $domain), $postDataMultipart);
return $this->safeHydrate($response, SendResponse::class);
return $this->hydrateResponse($response, SendResponse::class);
}
/**
@ -90,7 +90,7 @@ class Message extends HttpApi
$response = $this->httpGet($url, [], $headers);
return $this->safeHydrate($response, ShowResponse::class);
return $this->hydrateResponse($response, ShowResponse::class);
}
/**

View File

@ -20,7 +20,7 @@ trait Pagination
{
abstract protected function httpGet($path, array $parameters = [], array $requestHeaders = []);
abstract protected function safeHydrate(ResponseInterface $response, $className);
abstract protected function hydrateResponse(ResponseInterface $response, $className);
/**
* @param PagingProvider $response
@ -78,6 +78,6 @@ trait Pagination
$response = $this->httpGet($url);
return $this->safeHydrate($response, $class);
return $this->hydrateResponse($response, $class);
}
}

View File

@ -45,7 +45,7 @@ class Routes extends HttpApi
$response = $this->httpGet('/v3/routes', $params);
return $this->safeHydrate($response, IndexResponse::class);
return $this->hydrateResponse($response, IndexResponse::class);
}
/**
@ -61,7 +61,7 @@ class Routes extends HttpApi
$response = $this->httpGet(sprintf('/v3/routes/%s', $routeId));
return $this->safeHydrate($response, ShowResponse::class);
return $this->hydrateResponse($response, ShowResponse::class);
}
/**
@ -90,7 +90,7 @@ class Routes extends HttpApi
$response = $this->httpPost('/v3/routes', $params);
return $this->safeHydrate($response, CreateResponse::class);
return $this->hydrateResponse($response, CreateResponse::class);
}
/**
@ -136,7 +136,7 @@ class Routes extends HttpApi
$response = $this->httpPut(sprintf('/v3/routes/%s', $routeId), $params);
return $this->safeHydrate($response, UpdateResponse::class);
return $this->hydrateResponse($response, UpdateResponse::class);
}
/**
@ -152,6 +152,6 @@ class Routes extends HttpApi
$response = $this->httpDelete(sprintf('/v3/routes/%s', $routeId));
return $this->safeHydrate($response, DeleteResponse::class);
return $this->hydrateResponse($response, DeleteResponse::class);
}
}

View File

@ -32,7 +32,7 @@ class Stats extends HttpApi
$response = $this->httpGet(sprintf('/v3/%s/stats/total', rawurlencode($domain)), $params);
return $this->safeHydrate($response, TotalResponse::class);
return $this->hydrateResponse($response, TotalResponse::class);
}
/**
@ -47,6 +47,6 @@ class Stats extends HttpApi
$response = $this->httpGet(sprintf('/v3/%s/stats', rawurlencode($domain)), $params);
return $this->safeHydrate($response, AllResponse::class);
return $this->hydrateResponse($response, AllResponse::class);
}
}

View File

@ -43,7 +43,7 @@ class Bounce extends HttpApi
$response = $this->httpGet(sprintf('/v3/%s/bounces', $domain), $params);
return $this->safeHydrate($response, IndexResponse::class);
return $this->hydrateResponse($response, IndexResponse::class);
}
/**
@ -59,7 +59,7 @@ class Bounce extends HttpApi
$response = $this->httpGet(sprintf('/v3/%s/bounces/%s', $domain, $address));
return $this->safeHydrate($response, ShowResponse::class);
return $this->hydrateResponse($response, ShowResponse::class);
}
/**
@ -78,7 +78,7 @@ class Bounce extends HttpApi
$response = $this->httpPost(sprintf('/v3/%s/bounces', $domain), $params);
return $this->safeHydrate($response, CreateResponse::class);
return $this->hydrateResponse($response, CreateResponse::class);
}
/**
@ -94,7 +94,7 @@ class Bounce extends HttpApi
$response = $this->httpDelete(sprintf('/v3/%s/bounces/%s', $domain, $address));
return $this->safeHydrate($response, DeleteResponse::class);
return $this->hydrateResponse($response, DeleteResponse::class);
}
/**
@ -108,6 +108,6 @@ class Bounce extends HttpApi
$response = $this->httpDelete(sprintf('/v3/%s/bounces', $domain));
return $this->safeHydrate($response, DeleteResponse::class);
return $this->hydrateResponse($response, DeleteResponse::class);
}
}

View File

@ -43,7 +43,7 @@ class Complaint extends HttpApi
$response = $this->httpGet(sprintf('/v3/%s/complaints', $domain), $params);
return $this->safeHydrate($response, IndexResponse::class);
return $this->hydrateResponse($response, IndexResponse::class);
}
/**
@ -58,7 +58,7 @@ class Complaint extends HttpApi
Assert::stringNotEmpty($address);
$response = $this->httpGet(sprintf('/v3/%s/complaints/%s', $domain, $address));
return $this->safeHydrate($response, ShowResponse::class);
return $this->hydrateResponse($response, ShowResponse::class);
}
/**
@ -77,7 +77,7 @@ class Complaint extends HttpApi
$response = $this->httpPost(sprintf('/v3/%s/complaints', $domain), $params);
return $this->safeHydrate($response, CreateResponse::class);
return $this->hydrateResponse($response, CreateResponse::class);
}
/**
@ -93,7 +93,7 @@ class Complaint extends HttpApi
$response = $this->httpDelete(sprintf('/v3/%s/complaints/%s', $domain, $address));
return $this->safeHydrate($response, DeleteResponse::class);
return $this->hydrateResponse($response, DeleteResponse::class);
}
/**
@ -107,6 +107,6 @@ class Complaint extends HttpApi
$response = $this->httpDelete(sprintf('/v3/%s/complaints', $domain));
return $this->safeHydrate($response, DeleteResponse::class);
return $this->hydrateResponse($response, DeleteResponse::class);
}
}

View File

@ -43,7 +43,7 @@ class Unsubscribe extends HttpApi
$response = $this->httpGet(sprintf('/v3/%s/unsubscribes', $domain), $params);
return $this->safeHydrate($response, IndexResponse::class);
return $this->hydrateResponse($response, IndexResponse::class);
}
/**
@ -59,7 +59,7 @@ class Unsubscribe extends HttpApi
$response = $this->httpGet(sprintf('/v3/%s/unsubscribes/%s', $domain, $address));
return $this->safeHydrate($response, ShowResponse::class);
return $this->hydrateResponse($response, ShowResponse::class);
}
/**
@ -78,7 +78,7 @@ class Unsubscribe extends HttpApi
$response = $this->httpPost(sprintf('/v3/%s/unsubscribes', $domain), $params);
return $this->safeHydrate($response, CreateResponse::class);
return $this->hydrateResponse($response, CreateResponse::class);
}
/**
@ -94,7 +94,7 @@ class Unsubscribe extends HttpApi
$response = $this->httpDelete(sprintf('/v3/%s/unsubscribes/%s', $domain, $address));
return $this->safeHydrate($response, DeleteResponse::class);
return $this->hydrateResponse($response, DeleteResponse::class);
}
/**
@ -108,6 +108,6 @@ class Unsubscribe extends HttpApi
$response = $this->httpDelete(sprintf('/v3/%s/unsubscribes', $domain));
return $this->safeHydrate($response, DeleteResponse::class);
return $this->hydrateResponse($response, DeleteResponse::class);
}
}

View File

@ -43,7 +43,7 @@ class Tag extends HttpApi
$response = $this->httpGet(sprintf('/v3/%s/tags', $domain), $params);
return $this->safeHydrate($response, IndexResponse::class);
return $this->hydrateResponse($response, IndexResponse::class);
}
/**
@ -61,7 +61,7 @@ class Tag extends HttpApi
$response = $this->httpGet(sprintf('/v3/%s/tags/%s', $domain, $tag));
return $this->safeHydrate($response, ShowResponse::class);
return $this->hydrateResponse($response, ShowResponse::class);
}
/**
@ -85,7 +85,7 @@ class Tag extends HttpApi
$response = $this->httpPut(sprintf('/v3/%s/tags/%s', $domain, $tag), $params);
return $this->safeHydrate($response, UpdateResponse::class);
return $this->hydrateResponse($response, UpdateResponse::class);
}
/**
@ -105,7 +105,7 @@ class Tag extends HttpApi
$response = $this->httpGet(sprintf('/v3/%s/tags/%s/stats', $domain, $tag), $params);
return $this->safeHydrate($response, StatisticsResponse::class);
return $this->hydrateResponse($response, StatisticsResponse::class);
}
/**
@ -123,6 +123,6 @@ class Tag extends HttpApi
$response = $this->httpDelete(sprintf('/v3/%s/tags/%s', $domain, $tag));
return $this->safeHydrate($response, DeleteResponse::class);
return $this->hydrateResponse($response, DeleteResponse::class);
}
}

View File

@ -31,7 +31,7 @@ class Webhook extends HttpApi
Assert::notEmpty($domain);
$response = $this->httpGet(sprintf('/v3/domains/%s/webhooks', $domain));
return $this->safeHydrate($response, IndexResponse::class);
return $this->hydrateResponse($response, IndexResponse::class);
}
/**
@ -46,7 +46,7 @@ class Webhook extends HttpApi
Assert::notEmpty($webhook);
$response = $this->httpGet(sprintf('/v3/domains/%s/webhooks/%s', $domain, $webhook));
return $this->safeHydrate($response, ShowResponse::class);
return $this->hydrateResponse($response, ShowResponse::class);
}
/**
@ -69,7 +69,7 @@ class Webhook extends HttpApi
$response = $this->httpPost(sprintf('/v3/domains/%s/webhooks', $domain), $params);
return $this->safeHydrate($response, CreateResponse::class);
return $this->hydrateResponse($response, CreateResponse::class);
}
/**
@ -91,7 +91,7 @@ class Webhook extends HttpApi
$response = $this->httpPut(sprintf('/v3/domains/%s/webhooks/%s', $domain, $id), $params);
return $this->safeHydrate($response, UpdateResponse::class);
return $this->hydrateResponse($response, UpdateResponse::class);
}
/**
@ -107,6 +107,6 @@ class Webhook extends HttpApi
$response = $this->httpDelete(sprintf('/v3/domains/%s/webhooks/%s', $domain, $id));
return $this->safeHydrate($response, DeleteResponse::class);
return $this->hydrateResponse($response, DeleteResponse::class);
}
}

View File

@ -11,6 +11,6 @@ namespace Mailgun\Exception;
use Mailgun\Exception;
class DeserializeException extends \RuntimeException implements Exception
final class DeserializeException extends \RuntimeException implements Exception
{
}

View File

@ -10,29 +10,54 @@
namespace Mailgun\Exception;
use Mailgun\Exception;
use Psr\Http\Message\ResponseInterface;
/**
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*/
class HttpClientException extends \RuntimeException implements Exception
final class HttpClientException extends \RuntimeException implements Exception
{
public static function badRequest()
/**
* @var ResponseInterface|null
*/
private $response;
/**
* @param string $message
* @param int $code
* @param ResponseInterface|null $response
*/
public function __construct($message, $code, ResponseInterface $response = null)
{
return new self('The parameters passed to the API were invalid. Check your inputs!', 400);
parent::__construct($message, $code);
$this->response = $response;
}
public static function unauthorized()
public static function badRequest(ResponseInterface $response = null)
{
return new self('Your credentials are incorrect.', 401);
return new self('The parameters passed to the API were invalid. Check your inputs!', 400, $response);
}
public static function requestFailed()
public static function unauthorized(ResponseInterface $response = null)
{
return new self('Parameters were valid but request failed. Try again.', 402);
return new self('Your credentials are incorrect.', 401, $response);
}
public static function notFound()
public static function requestFailed(ResponseInterface $response = null)
{
return new self('The endpoint you tried to access does not exist. Check your URL.', 404);
return new self('Parameters were valid but request failed. Try again.', 402, $response);
}
public static function notFound(ResponseInterface $response = null)
{
return new self('The endpoint you tried to access does not exist. Check your URL.', 404, $response);
}
/**
* @return ResponseInterface
*/
public function getResponse()
{
return $this->response;
}
}

View File

@ -14,7 +14,7 @@ use Mailgun\Exception;
/**
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*/
class HttpServerException extends \RuntimeException implements Exception
final class HttpServerException extends \RuntimeException implements Exception
{
public static function serverError($httpStatus = 500)
{

View File

@ -14,6 +14,6 @@ use Mailgun\Exception;
/**
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*/
class InvalidArgumentException extends \InvalidArgumentException implements Exception
final class InvalidArgumentException extends \InvalidArgumentException implements Exception
{
}

View File

@ -0,0 +1,19 @@
<?php
/*
* Copyright (C) 2013-2016 Mailgun
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
namespace Mailgun\Exception;
use Mailgun\Exception;
/**
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*/
final class UnknownErrorException extends \Exception implements Exception
{
}

View File

@ -25,7 +25,7 @@ class ArrayHydrator implements Hydrator
*
* @return array
*/
public function deserialize(ResponseInterface $response, $class)
public function hydrate(ResponseInterface $response, $class)
{
$body = $response->getBody()->__toString();
if (strpos($response->getHeaderLine('Content-Type'), 'application/json') !== 0) {

View File

@ -22,5 +22,5 @@ interface Hydrator
*
* @return mixed
*/
public function deserialize(ResponseInterface $response, $class);
public function hydrate(ResponseInterface $response, $class);
}

View File

@ -26,7 +26,7 @@ class ModelHydrator implements Hydrator
*
* @return ResponseInterface
*/
public function deserialize(ResponseInterface $response, $class)
public function hydrate(ResponseInterface $response, $class)
{
$body = $response->getBody()->__toString();
$contentType = $response->getHeaderLine('Content-Type');

View File

@ -24,7 +24,7 @@ class NoopHydrator implements Hydrator
*
* @throws \LogicException
*/
public function deserialize(ResponseInterface $response, $class)
public function hydrate(ResponseInterface $response, $class)
{
throw new \LogicException('The NoopHydrator should never be called');
}

View File

@ -59,7 +59,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
->getMock();
$hydrator = $this->getMockBuilder('Mailgun\Hydrator\Hydrator')
->setMethods(['deserialize'])
->setMethods(['hydrate'])
->getMock();
return $this->getMockBuilder($this->getApiClass())