From e78fcc2219a4909c13a1105a737fadaa902a926a Mon Sep 17 00:00:00 2001 From: Simon Podlipsky Date: Wed, 30 Oct 2024 16:46:43 +0100 Subject: [PATCH 01/10] feat: introduce UnexpectedResponse exception --- CHANGELOG.md | 2 ++ src/Error/UnexpectedResponse.php | 39 +++++++++++++++++++++++++ src/Response.php | 4 ++- tests/Unit/ResponseTest.php | 7 ++++- tests/generate-and-approve-examples.php | 2 +- 5 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 src/Error/UnexpectedResponse.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a9c1768..1934a2f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Introduce UnexpectedResponse exception + ## v0.34.0 ### Changed diff --git a/src/Error/UnexpectedResponse.php b/src/Error/UnexpectedResponse.php new file mode 100644 index 00000000..2b320dd0 --- /dev/null +++ b/src/Error/UnexpectedResponse.php @@ -0,0 +1,39 @@ +> */ + public array $responseHeaders; + + public static function statusCode( + ResponseInterface $response + ): self { + $statusCode = $response->getStatusCode(); + $responseBody = $response->getBody()->__toString(); + + $jsonEncodedHeaders = \Safe\json_encode($response->getHeaders(), JSON_PRETTY_PRINT); + + $self = new self( + \Safe\sprintf( + "Unexpected HTTP status code received: %d. Reason: \n%s\nHeaders:\n" + . $jsonEncodedHeaders, + $statusCode, + $responseBody, + ), + ); + $self->statusCode = $statusCode; + /** @phpstan-ignore assign.propertyType */ + $self->responseHeaders = $response->getHeaders(); + $self->responseBody = $responseBody; + + return $self; + } +} diff --git a/src/Response.php b/src/Response.php index 1ffe5adf..65831916 100644 --- a/src/Response.php +++ b/src/Response.php @@ -6,6 +6,7 @@ use Psr\Http\Message\ResponseInterface; use Safe\Exceptions\JsonException; use Spawnia\Sailor\Error\InvalidDataException; +use Spawnia\Sailor\Error\UnexpectedResponse; /** * Represents a response sent by a GraphQL server. @@ -29,10 +30,11 @@ class Response /** This entry, if set, must have a map as its value. */ public ?\stdClass $extensions; + /** @throws UnexpectedResponse */ public static function fromResponseInterface(ResponseInterface $response): self { if ($response->getStatusCode() !== 200) { - throw new InvalidDataException("Response must have status code 200, got: {$response->getStatusCode()}"); + throw UnexpectedResponse::statusCode($response); } return self::fromJson( diff --git a/tests/Unit/ResponseTest.php b/tests/Unit/ResponseTest.php index 2194f8a8..4746aee3 100644 --- a/tests/Unit/ResponseTest.php +++ b/tests/Unit/ResponseTest.php @@ -6,6 +6,7 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; use Spawnia\Sailor\Error\InvalidDataException; +use Spawnia\Sailor\Error\UnexpectedResponse; use Spawnia\Sailor\Response; use Spawnia\Sailor\Tests\TestCase; @@ -33,10 +34,14 @@ public function testFromResponseInterfaceNon200(): void { /** @var MockObject&ResponseInterface $httpResponse */ $httpResponse = self::createMock(ResponseInterface::class); + $httpResponse->method('getHeaders') + ->willReturn([]); + $httpResponse->method('getBody') + ->willReturn(self::createMock(StreamInterface::class)); $httpResponse->method('getStatusCode') ->willReturn(500); - self::expectException(InvalidDataException::class); + self::expectException(UnexpectedResponse::class); Response::fromResponseInterface($httpResponse); } diff --git a/tests/generate-and-approve-examples.php b/tests/generate-and-approve-examples.php index 292266be..b39dc702 100755 --- a/tests/generate-and-approve-examples.php +++ b/tests/generate-and-approve-examples.php @@ -12,5 +12,5 @@ shell_exec("rm -rf {$expectedPath}"); $generatedPath = Examples::generatedPath($example); - shell_exec("cp --recursive {$generatedPath} {$expectedPath}"); + shell_exec("cp -R {$generatedPath} {$expectedPath}"); } From 1ef36a0a34b6535e71f4a4f5ab39e41c7dfe8f01 Mon Sep 17 00:00:00 2001 From: Simon Podlipsky Date: Mon, 4 Nov 2024 13:59:18 +0100 Subject: [PATCH 02/10] Apply suggestions from code review Co-authored-by: Benedikt Franke --- src/Error/UnexpectedResponse.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Error/UnexpectedResponse.php b/src/Error/UnexpectedResponse.php index 2b320dd0..fb6e2bdb 100644 --- a/src/Error/UnexpectedResponse.php +++ b/src/Error/UnexpectedResponse.php @@ -13,9 +13,7 @@ class UnexpectedResponse extends \Exception /** @var array> */ public array $responseHeaders; - public static function statusCode( - ResponseInterface $response - ): self { + public static function statusCode(ResponseInterface $response): self { $statusCode = $response->getStatusCode(); $responseBody = $response->getBody()->__toString(); @@ -30,8 +28,7 @@ public static function statusCode( ), ); $self->statusCode = $statusCode; - /** @phpstan-ignore assign.propertyType */ - $self->responseHeaders = $response->getHeaders(); + $self->responseHeaders = $response->getHeaders(); // @phpstan-ignore assign.propertyType (an explanation why it is a false-positive) $self->responseBody = $responseBody; return $self; From 5e63d5b4a6637e2d0d9087ced64878fd1370cad1 Mon Sep 17 00:00:00 2001 From: simPod Date: Mon, 4 Nov 2024 12:59:45 +0000 Subject: [PATCH 03/10] Apply php-cs-fixer changes --- src/Error/UnexpectedResponse.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Error/UnexpectedResponse.php b/src/Error/UnexpectedResponse.php index fb6e2bdb..d1c17972 100644 --- a/src/Error/UnexpectedResponse.php +++ b/src/Error/UnexpectedResponse.php @@ -13,7 +13,8 @@ class UnexpectedResponse extends \Exception /** @var array> */ public array $responseHeaders; - public static function statusCode(ResponseInterface $response): self { + public static function statusCode(ResponseInterface $response): self + { $statusCode = $response->getStatusCode(); $responseBody = $response->getBody()->__toString(); From cc877e60b2d2b4504d54203ab8bd1e79c3d3444f Mon Sep 17 00:00:00 2001 From: Simon Podlipsky Date: Mon, 4 Nov 2024 13:59:38 +0100 Subject: [PATCH 04/10] remove explanation --- src/Error/UnexpectedResponse.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Error/UnexpectedResponse.php b/src/Error/UnexpectedResponse.php index d1c17972..328b88d6 100644 --- a/src/Error/UnexpectedResponse.php +++ b/src/Error/UnexpectedResponse.php @@ -29,7 +29,7 @@ public static function statusCode(ResponseInterface $response): self ), ); $self->statusCode = $statusCode; - $self->responseHeaders = $response->getHeaders(); // @phpstan-ignore assign.propertyType (an explanation why it is a false-positive) + $self->responseHeaders = $response->getHeaders(); // @phpstan-ignore assign.propertyType $self->responseBody = $responseBody; return $self; From 11a344cc026f00c80dee62fa91724f8d3d67ae4e Mon Sep 17 00:00:00 2001 From: Simon Podlipsky Date: Mon, 4 Nov 2024 14:00:22 +0100 Subject: [PATCH 05/10] interpolation --- src/Error/UnexpectedResponse.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Error/UnexpectedResponse.php b/src/Error/UnexpectedResponse.php index 328b88d6..79a64084 100644 --- a/src/Error/UnexpectedResponse.php +++ b/src/Error/UnexpectedResponse.php @@ -21,12 +21,7 @@ public static function statusCode(ResponseInterface $response): self $jsonEncodedHeaders = \Safe\json_encode($response->getHeaders(), JSON_PRETTY_PRINT); $self = new self( - \Safe\sprintf( - "Unexpected HTTP status code received: %d. Reason: \n%s\nHeaders:\n" - . $jsonEncodedHeaders, - $statusCode, - $responseBody, - ), + "Unexpected HTTP status code received: {$statusCode}. Reason: \n{$responseBody}\nHeaders:\n{$jsonEncodedHeaders}", ); $self->statusCode = $statusCode; $self->responseHeaders = $response->getHeaders(); // @phpstan-ignore assign.propertyType From f8f6eb60406ba4b3c768c2b2ee80a7b5248fa96d Mon Sep 17 00:00:00 2001 From: Benedikt Franke Date: Thu, 7 Nov 2024 16:30:46 +0100 Subject: [PATCH 06/10] Using -R over --recursive for macOS compatibility --- tests/generate-and-approve-examples.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/generate-and-approve-examples.php b/tests/generate-and-approve-examples.php index b39dc702..3a6731b7 100755 --- a/tests/generate-and-approve-examples.php +++ b/tests/generate-and-approve-examples.php @@ -12,5 +12,6 @@ shell_exec("rm -rf {$expectedPath}"); $generatedPath = Examples::generatedPath($example); + # Using -R over --recursive for macOS compatibility shell_exec("cp -R {$generatedPath} {$expectedPath}"); } From d37835ab59e82849a2669201bdc0609b54e09e98 Mon Sep 17 00:00:00 2001 From: spawnia Date: Thu, 7 Nov 2024 15:31:18 +0000 Subject: [PATCH 07/10] Apply php-cs-fixer changes --- tests/generate-and-approve-examples.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/generate-and-approve-examples.php b/tests/generate-and-approve-examples.php index 3a6731b7..01f2765b 100755 --- a/tests/generate-and-approve-examples.php +++ b/tests/generate-and-approve-examples.php @@ -12,6 +12,6 @@ shell_exec("rm -rf {$expectedPath}"); $generatedPath = Examples::generatedPath($example); - # Using -R over --recursive for macOS compatibility + // Using -R over --recursive for macOS compatibility shell_exec("cp -R {$generatedPath} {$expectedPath}"); } From c27377fa41f55f873f11b2a8c828d6150f71d287 Mon Sep 17 00:00:00 2001 From: Simon Podlipsky Date: Fri, 8 Nov 2024 09:12:40 +0100 Subject: [PATCH 08/10] rework constructor --- src/Error/UnexpectedResponse.php | 21 +++++++++++---------- src/Response.php | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Error/UnexpectedResponse.php b/src/Error/UnexpectedResponse.php index 79a64084..9d92dc6f 100644 --- a/src/Error/UnexpectedResponse.php +++ b/src/Error/UnexpectedResponse.php @@ -3,6 +3,7 @@ namespace Spawnia\Sailor\Error; use Psr\Http\Message\ResponseInterface; +use const JSON_PRETTY_PRINT; class UnexpectedResponse extends \Exception { @@ -10,23 +11,23 @@ class UnexpectedResponse extends \Exception public string $responseBody = ''; - /** @var array> */ + /** @var array> */ public array $responseHeaders; - public static function statusCode(ResponseInterface $response): self + public function __construct(ResponseInterface $response) { $statusCode = $response->getStatusCode(); $responseBody = $response->getBody()->__toString(); + $responseHeaders = $response->getHeaders(); - $jsonEncodedHeaders = \Safe\json_encode($response->getHeaders(), JSON_PRETTY_PRINT); + $this->statusCode = $statusCode; + $this->responseBody = $responseBody; + $this->responseHeaders = $responseHeaders; - $self = new self( - "Unexpected HTTP status code received: {$statusCode}. Reason: \n{$responseBody}\nHeaders:\n{$jsonEncodedHeaders}", + parent::__construct( + "Unexpected response received: {$statusCode}. Reason: \n{$responseBody}\nHeaders:\n" . \Safe\json_encode($responseHeaders, JSON_PRETTY_PRINT), ); - $self->statusCode = $statusCode; - $self->responseHeaders = $response->getHeaders(); // @phpstan-ignore assign.propertyType - $self->responseBody = $responseBody; - - return $self; } + + } diff --git a/src/Response.php b/src/Response.php index 65831916..2393a655 100644 --- a/src/Response.php +++ b/src/Response.php @@ -34,7 +34,7 @@ class Response public static function fromResponseInterface(ResponseInterface $response): self { if ($response->getStatusCode() !== 200) { - throw UnexpectedResponse::statusCode($response); + throw new UnexpectedResponse($response); } return self::fromJson( From 0ab6b4fb42d47a053778b1aee4a356976af0e676 Mon Sep 17 00:00:00 2001 From: simPod Date: Fri, 8 Nov 2024 08:13:10 +0000 Subject: [PATCH 09/10] Apply php-cs-fixer changes --- src/Error/UnexpectedResponse.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Error/UnexpectedResponse.php b/src/Error/UnexpectedResponse.php index 9d92dc6f..08a09add 100644 --- a/src/Error/UnexpectedResponse.php +++ b/src/Error/UnexpectedResponse.php @@ -3,7 +3,6 @@ namespace Spawnia\Sailor\Error; use Psr\Http\Message\ResponseInterface; -use const JSON_PRETTY_PRINT; class UnexpectedResponse extends \Exception { @@ -25,9 +24,7 @@ public function __construct(ResponseInterface $response) $this->responseHeaders = $responseHeaders; parent::__construct( - "Unexpected response received: {$statusCode}. Reason: \n{$responseBody}\nHeaders:\n" . \Safe\json_encode($responseHeaders, JSON_PRETTY_PRINT), + "Unexpected response received: {$statusCode}. Reason: \n{$responseBody}\nHeaders:\n" . \Safe\json_encode($responseHeaders, \JSON_PRETTY_PRINT), ); } - - } From 1bffaf632cf5ea22d5b29e1b5b2897da1ce697c6 Mon Sep 17 00:00:00 2001 From: Benedikt Franke Date: Fri, 8 Nov 2024 12:23:21 +0100 Subject: [PATCH 10/10] dumb constructor, smart initializer --- src/Error/UnexpectedResponse.php | 30 ++++++++++++++++++++++-------- src/Response.php | 2 +- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/Error/UnexpectedResponse.php b/src/Error/UnexpectedResponse.php index 08a09add..e9861f7b 100644 --- a/src/Error/UnexpectedResponse.php +++ b/src/Error/UnexpectedResponse.php @@ -6,25 +6,39 @@ class UnexpectedResponse extends \Exception { - public int $statusCode = 0; + public int $statusCode; - public string $responseBody = ''; + public string $responseBody; /** @var array> */ public array $responseHeaders; - public function __construct(ResponseInterface $response) + /** @param array> $responseHeaders */ + public function __construct( + string $message, + int $statusCode, + string $responseBody, + array $responseHeaders + ) { + parent::__construct($message); + $this->statusCode = $statusCode; + $this->responseBody = $responseBody; + $this->responseHeaders = $responseHeaders; + } + + public static function statusCode(ResponseInterface $response): self { $statusCode = $response->getStatusCode(); $responseBody = $response->getBody()->__toString(); $responseHeaders = $response->getHeaders(); - $this->statusCode = $statusCode; - $this->responseBody = $responseBody; - $this->responseHeaders = $responseHeaders; + $jsonEncodedHeaders = \Safe\json_encode($responseHeaders, JSON_PRETTY_PRINT); - parent::__construct( - "Unexpected response received: {$statusCode}. Reason: \n{$responseBody}\nHeaders:\n" . \Safe\json_encode($responseHeaders, \JSON_PRETTY_PRINT), + return new self( + "Unexpected HTTP status code received: {$statusCode}.\nReason:\n{$responseBody}\nHeaders:\n{$jsonEncodedHeaders}", + $statusCode, + $responseBody, + $responseHeaders, ); } } diff --git a/src/Response.php b/src/Response.php index 2393a655..65831916 100644 --- a/src/Response.php +++ b/src/Response.php @@ -34,7 +34,7 @@ class Response public static function fromResponseInterface(ResponseInterface $response): self { if ($response->getStatusCode() !== 200) { - throw new UnexpectedResponse($response); + throw UnexpectedResponse::statusCode($response); } return self::fromJson(