From ff80f32f72f6d9a7695fc26dbb6acd3ece059b14 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Fri, 5 Oct 2018 19:19:44 +0200 Subject: [PATCH] Created json_encode function which always maps to array and converts errors into exceptions --- module/Common/functions/functions.php | 15 ++++++++++++++- module/Common/src/Exception/WrongIpException.php | 4 +++- .../Common/src/Service/IpApiLocationResolver.php | 9 +++++++-- .../Rest/src/Middleware/BodyParserMiddleware.php | 13 ++----------- .../Rest/test/Action/Tag/ListTagsActionTest.php | 3 ++- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/module/Common/functions/functions.php b/module/Common/functions/functions.php index 389c4636..e28e4fb2 100644 --- a/module/Common/functions/functions.php +++ b/module/Common/functions/functions.php @@ -3,8 +3,11 @@ declare(strict_types=1); namespace Shlinkio\Shlink\Common; +use const JSON_ERROR_NONE; use function getenv; use function in_array; +use function json_last_error; +use function json_last_error_msg; use function strtolower; use function trim; @@ -42,7 +45,17 @@ function env($key, $default = null) return trim($value); } -function contains($needle, array $haystack) +function contains($needle, array $haystack): bool { return in_array($needle, $haystack, true); } + +function json_decode(string $json, int $depth = 512, int $options = 0): array +{ + $data = \json_decode($json, true, $depth, $options); + if (JSON_ERROR_NONE !== json_last_error()) { + throw new Exception\InvalidArgumentException('Error decoding JSON: ' . json_last_error_msg()); + } + + return $data; +} diff --git a/module/Common/src/Exception/WrongIpException.php b/module/Common/src/Exception/WrongIpException.php index d31a2436..2d98f1ea 100644 --- a/module/Common/src/Exception/WrongIpException.php +++ b/module/Common/src/Exception/WrongIpException.php @@ -3,10 +3,12 @@ declare(strict_types=1); namespace Shlinkio\Shlink\Common\Exception; +use function sprintf; + class WrongIpException extends RuntimeException { public static function fromIpAddress($ipAddress, \Throwable $prev = null): self { - return new self(\sprintf('Provided IP "%s" is invalid', $ipAddress), 0, $prev); + return new self(sprintf('Provided IP "%s" is invalid', $ipAddress), 0, $prev); } } diff --git a/module/Common/src/Service/IpApiLocationResolver.php b/module/Common/src/Service/IpApiLocationResolver.php index d801a2e8..58544c29 100644 --- a/module/Common/src/Service/IpApiLocationResolver.php +++ b/module/Common/src/Service/IpApiLocationResolver.php @@ -5,7 +5,10 @@ namespace Shlinkio\Shlink\Common\Service; use GuzzleHttp\Client; use GuzzleHttp\Exception\GuzzleException; +use Shlinkio\Shlink\Common\Exception\InvalidArgumentException; use Shlinkio\Shlink\Common\Exception\WrongIpException; +use function Shlinkio\Shlink\Common\json_decode; +use function sprintf; class IpApiLocationResolver implements IpLocationResolverInterface { @@ -29,10 +32,12 @@ class IpApiLocationResolver implements IpLocationResolverInterface public function resolveIpLocation(string $ipAddress): array { try { - $response = $this->httpClient->get(\sprintf(self::SERVICE_PATTERN, $ipAddress)); - return $this->mapFields(\json_decode((string) $response->getBody(), true)); + $response = $this->httpClient->get(sprintf(self::SERVICE_PATTERN, $ipAddress)); + return $this->mapFields(json_decode((string) $response->getBody())); } catch (GuzzleException $e) { throw WrongIpException::fromIpAddress($ipAddress, $e); + } catch (InvalidArgumentException $e) { + throw new WrongIpException('IP-API returned invalid body while locating IP address', 0, $e); } } diff --git a/module/Rest/src/Middleware/BodyParserMiddleware.php b/module/Rest/src/Middleware/BodyParserMiddleware.php index 9b236e1f..5d9b883f 100644 --- a/module/Rest/src/Middleware/BodyParserMiddleware.php +++ b/module/Rest/src/Middleware/BodyParserMiddleware.php @@ -8,15 +8,11 @@ use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; -use Shlinkio\Shlink\Rest\Exception\RuntimeException; use function array_shift; use function explode; -use function json_decode; -use function json_last_error; -use function json_last_error_msg; use function parse_str; use function Shlinkio\Shlink\Common\contains; -use function sprintf; +use function Shlinkio\Shlink\Common\json_decode; use function trim; class BodyParserMiddleware implements MiddlewareInterface, RequestMethodInterface @@ -67,7 +63,6 @@ class BodyParserMiddleware implements MiddlewareInterface, RequestMethodInterfac /** * @param Request $request * @return Request - * @throws RuntimeException */ private function parseFromJson(Request $request): Request { @@ -76,11 +71,7 @@ class BodyParserMiddleware implements MiddlewareInterface, RequestMethodInterfac return $request; } - $parsedJson = json_decode($rawBody, true); - if (json_last_error() !== JSON_ERROR_NONE) { - throw new RuntimeException(sprintf('Error when parsing JSON request body: %s', json_last_error_msg())); - } - + $parsedJson = json_decode($rawBody); return $request->withParsedBody($parsedJson); } diff --git a/module/Rest/test/Action/Tag/ListTagsActionTest.php b/module/Rest/test/Action/Tag/ListTagsActionTest.php index 7fb73404..db3c52c8 100644 --- a/module/Rest/test/Action/Tag/ListTagsActionTest.php +++ b/module/Rest/test/Action/Tag/ListTagsActionTest.php @@ -10,6 +10,7 @@ use Shlinkio\Shlink\Core\Entity\Tag; use Shlinkio\Shlink\Core\Service\Tag\TagServiceInterface; use Shlinkio\Shlink\Rest\Action\Tag\ListTagsAction; use Zend\Diactoros\ServerRequestFactory; +use function Shlinkio\Shlink\Common\json_decode; class ListTagsActionTest extends TestCase { @@ -42,7 +43,7 @@ class ListTagsActionTest extends TestCase 'tags' => [ 'data' => ['foo', 'bar'], ], - ], \json_decode((string) $resp->getBody(), true)); + ], json_decode((string) $resp->getBody())); $listTags->shouldHaveBeenCalled(); } }