Skip to content

Commit

Permalink
minor #35822 [HttpClient][DX] Add URL context to JsonException messag…
Browse files Browse the repository at this point in the history
…es (GromNaN)

This PR was squashed before being merged into the 4.4 branch.

Discussion
----------

[HttpClient][DX] Add URL context to JsonException messages

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | #35762 (comment)
| License       | MIT
| Doc PR        | N/A

In order to help when debugging incorrect JSON responses, this PR adds the requested URL to the error message.

Before: `Syntax Error`
After: `JSON error: Syntax error, from "https://example.com/file.json".`
See the 2nd commit for full diff in new unit tests

Commits
-------

0653917 [HttpClient][DX] Add URL context to JsonException messages
  • Loading branch information
nicolas-grekas committed Feb 25, 2020
2 parents 8a678f6 + 0653917 commit cad3f10
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 4 deletions.
8 changes: 4 additions & 4 deletions src/Symfony/Component/HttpClient/Response/ResponseTrait.php
Expand Up @@ -147,21 +147,21 @@ public function toArray(bool $throw = true): array
$contentType = $this->headers['content-type'][0] ?? 'application/json';

if (!preg_match('/\bjson\b/i', $contentType)) {
throw new JsonException(sprintf('Response content-type is "%s" while a JSON-compatible one was expected.', $contentType));
throw new JsonException(sprintf('Response content-type is "%s" while a JSON-compatible one was expected for "%s".', $contentType, $this->getInfo('url')));
}

try {
$content = json_decode($content, true, 512, JSON_BIGINT_AS_STRING | (\PHP_VERSION_ID >= 70300 ? JSON_THROW_ON_ERROR : 0));
} catch (\JsonException $e) {
throw new JsonException($e->getMessage(), $e->getCode());
throw new JsonException(sprintf('%s for "%s".', $e->getMessage(), $this->getInfo('url')), $e->getCode());
}

if (\PHP_VERSION_ID < 70300 && JSON_ERROR_NONE !== json_last_error()) {
throw new JsonException(json_last_error_msg(), json_last_error());
throw new JsonException(sprintf('%s for "%s".', json_last_error_msg(), $this->getInfo('url')), json_last_error());
}

if (!\is_array($content)) {
throw new JsonException(sprintf('JSON content was expected to decode to an array, %s returned.', \gettype($content)));
throw new JsonException(sprintf('JSON content was expected to decode to an array, %s returned for "%s".', \gettype($content), $this->getInfo('url')));
}

if (null !== $this->content) {
Expand Down
@@ -0,0 +1,68 @@
<?php

namespace Symfony\Component\HttpClient\Tests\Response;

use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpClient\Exception\JsonException;
use Symfony\Component\HttpClient\Response\MockResponse;

/**
* Test methods from Symfony\Component\HttpClient\Response\ResponseTrait.
*/
class MockResponseTest extends TestCase
{
public function testToArray()
{
$data = ['color' => 'orange', 'size' => 42];
$response = new MockResponse(json_encode($data));
$response = MockResponse::fromRequest('GET', 'https://example.com/file.json', [], $response);

$this->assertSame($data, $response->toArray());
}

/**
* @dataProvider toArrayErrors
*/
public function testToArrayError($content, $responseHeaders, $message)
{
$this->expectException(JsonException::class);
$this->expectExceptionMessage($message);

$response = new MockResponse($content, ['response_headers' => $responseHeaders]);
$response = MockResponse::fromRequest('GET', 'https://example.com/file.json', [], $response);
$response->toArray();
}

public function toArrayErrors()
{
yield [
'content' => '{}',
'responseHeaders' => ['content-type' => 'plain/text'],
'message' => 'Response content-type is "plain/text" while a JSON-compatible one was expected for "https://example.com/file.json".',
];

yield [
'content' => 'not json',
'responseHeaders' => [],
'message' => 'Syntax error for "https://example.com/file.json".',
];

yield [
'content' => '[1,2}',
'responseHeaders' => [],
'message' => 'State mismatch (invalid or malformed JSON) for "https://example.com/file.json".',
];

yield [
'content' => '"not an array"',
'responseHeaders' => [],
'message' => 'JSON content was expected to decode to an array, string returned for "https://example.com/file.json".',
];

yield [
'content' => '8',
'responseHeaders' => [],
'message' => 'JSON content was expected to decode to an array, integer returned for "https://example.com/file.json".',
];
}
}

0 comments on commit cad3f10

Please sign in to comment.