Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Response: add decode_body() method #559

Merged
merged 12 commits into from
Oct 11, 2021
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
"docs": "https://requests.ryanmccue.info/"
},
"require": {
"php": ">=5.6"
"php": ">=5.6",
"ext-json": "*"
},
"require-dev": {
"requests/test-server": "dev-master",
Expand Down
33 changes: 33 additions & 0 deletions src/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,37 @@ public function throw_for_status($allow_redirects = true) {
throw new $exception(null, $this);
}
}

/**
* JSON decode the response body.
*
* The method parameters are the same as those for the PHP native `json_decode()` function.
*
* @link https://php.net/json-decode
*
* @param ?bool $associative Optional. When `true`, JSON objects will be returned as associative arrays;
* When `false`, JSON objects will be returned as objects.
* When `null`, JSON objects will be returned as associative arrays
* or objects depending on whether `JSON_OBJECT_AS_ARRAY` is set in the flags.
* Defaults to `true` (in contrast to the PHP native default of `null`).
* @param int $depth Optional. Maximum nesting depth of the structure being decoded.
* Defaults to `512`.
* @param int $options Optional. Bitmask of JSON_BIGINT_AS_STRING, JSON_INVALID_UTF8_IGNORE,
* JSON_INVALID_UTF8_SUBSTITUTE, JSON_OBJECT_AS_ARRAY, JSON_THROW_ON_ERROR.
* Defaults to `0` (no options set).
*
* @return array
*
* @throws \WpOrg\Requests\Exception If `$this->body` is not valid json.
*/
public function decode_body($associative = true, $depth = 512, $options = 0) {
$data = json_decode($this->body, $associative, $depth, $options);

if (json_last_error() !== JSON_ERROR_NONE) {
$last_error = json_last_error_msg();
throw new Exception('Unable to parse JSON data: ' . $last_error, 'response.invalid', $this);
}

return $data;
}
}
78 changes: 78 additions & 0 deletions tests/ResponseTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

namespace WpOrg\Requests\Tests;

use WpOrg\Requests\Exception;
use WpOrg\Requests\Response;
use WpOrg\Requests\Tests\TestCase;

/**
* @coversDefaultClass \WpOrg\Requests\Response
*/
final class ResponseTest extends TestCase {

/**
* Verify that an exception is thrown when the body content is invalid as JSON.
*
* @requires extension json
*
* @covers ::decode_body
*
* @dataProvider dataInvalidJsonResponse
*
* @param mixed $body Data to use as the Response body.
*
* @return void
*/
public function testInvalidJsonResponse($body) {
$this->expectException(Exception::class);
$this->expectExceptionMessage('Unable to parse JSON data: ');

$response = new Response();
$response->body = $body;

$response->decode_body();
}

/**
* Data provider.
*
* @return array
*/
public function dataInvalidJsonResponse() {
$data = array(
'text string, not JSON (syntax error)' => array('Invalid JSON'),
'invalid JSON: single quotes (syntax error)' => array("{ 'bar': 'baz' }"),
);

// An empty string is only regarded as invalid JSON since PHP 7.0.
if (PHP_VERSION_ID >= 70000) {
$data['empty string (syntax error)'] = array('');
}

return $data;
}

/**
* Verify correctly decoding a body in valid JSON.
*
* @requires extension json
*
* @covers ::decode_body
*
* @return void
*/
public function testJsonResponse() {
$response = new Response();
$response->body = '{"success": false, "error": [], "data": null}';
$decoded_body = $response->decode_body();

$expected = array(
'success' => false,
'error' => array(),
'data' => null,
);

$this->assertSame($expected, $decoded_body);
}
}