diff --git a/lib/Github/HttpClient/Plugin/GithubExceptionThrower.php b/lib/Github/HttpClient/Plugin/GithubExceptionThrower.php index b16ec620308..4a68aa3921f 100644 --- a/lib/Github/HttpClient/Plugin/GithubExceptionThrower.php +++ b/lib/Github/HttpClient/Plugin/GithubExceptionThrower.php @@ -29,6 +29,8 @@ public function doHandleRequest(RequestInterface $request, callable $next, calla { return $next($request)->then(function (ResponseInterface $response) use ($request) { if ($response->getStatusCode() < 400 || $response->getStatusCode() > 600) { + $this->checkGraphqlErrors($response); + return $response; } @@ -117,4 +119,38 @@ public function doHandleRequest(RequestInterface $request, callable $next, calla throw new RuntimeException(isset($content['message']) ? $content['message'] : $content, $response->getStatusCode()); }); } + + /** + * The graphql api doesn't return a 5xx http status for errors. Instead it returns a 200 with an error body. + * + * @throws RuntimeException + */ + private function checkGraphqlErrors(ResponseInterface $response): void + { + if ($response->getStatusCode() !== 200) { + return; + } + + $content = ResponseMediator::getContent($response); + if (!is_array($content)) { + return; + } + + if (!isset($content['errors']) || !is_array($content['errors'])) { + return; + } + + $errors = []; + foreach ($content['errors'] as $error) { + if (isset($error['message'])) { + $errors[] = $error['message']; + } + } + + if (empty($errors)) { + return; + } + + throw new RuntimeException(implode(', ', $errors)); + } } diff --git a/test/Github/Tests/HttpClient/Plugin/GithubExceptionThrowerTest.php b/test/Github/Tests/HttpClient/Plugin/GithubExceptionThrowerTest.php index 7011e1fe6bb..9c1de98d59d 100644 --- a/test/Github/Tests/HttpClient/Plugin/GithubExceptionThrowerTest.php +++ b/test/Github/Tests/HttpClient/Plugin/GithubExceptionThrowerTest.php @@ -154,6 +154,29 @@ public static function responseProvider() ), 'exception' => new \Github\Exception\RuntimeException('Error message', 555), ], + 'Graphql error response (200)' => [ + 'response' => new Response( + 200, + [ + 'content-type' => 'application/json', + ], + json_encode( + [ + 'errors' => [ + [ + ['path' => ['query', 'repository']], + 'message' => 'Field "xxxx" doesn\'t exist on type "Issue"', + ], + [ + ['path' => ['query', 'repository']], + 'message' => 'Field "dummy" doesn\'t exist on type "PullRequest"', + ], + ], + ] + ) + ), + 'exception' => new \Github\Exception\RuntimeException('Field "xxxx" doesn\'t exist on type "Issue", Field "dummy" doesn\'t exist on type "PullRequest"'), + ], ]; } }