minor #35822 [HttpClient][DX] Add URL context to JsonException messages (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 | https://github.com/symfony/symfony/pull/35762#issuecomment-589770016
| 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
-------
06539173e7
[HttpClient][DX] Add URL context to JsonException messages
This commit is contained in:
commit
cad3f10cdb
@ -147,21 +147,21 @@ trait ResponseTrait
|
|||||||
$contentType = $this->headers['content-type'][0] ?? 'application/json';
|
$contentType = $this->headers['content-type'][0] ?? 'application/json';
|
||||||
|
|
||||||
if (!preg_match('/\bjson\b/i', $contentType)) {
|
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 {
|
try {
|
||||||
$content = json_decode($content, true, 512, JSON_BIGINT_AS_STRING | (\PHP_VERSION_ID >= 70300 ? JSON_THROW_ON_ERROR : 0));
|
$content = json_decode($content, true, 512, JSON_BIGINT_AS_STRING | (\PHP_VERSION_ID >= 70300 ? JSON_THROW_ON_ERROR : 0));
|
||||||
} catch (\JsonException $e) {
|
} 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()) {
|
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)) {
|
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) {
|
if (null !== $this->content) {
|
||||||
|
@ -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".',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user