diff --git a/src/http-client/src/Response.php b/src/http-client/src/Response.php index 9abc4b5ff..95aa125d3 100644 --- a/src/http-client/src/Response.php +++ b/src/http-client/src/Response.php @@ -33,6 +33,11 @@ class Response implements ArrayAccess, Stringable */ protected array $decoded = []; + /** + * The custom decode callback. + */ + protected ?Closure $decodeUsing = null; + /** * The request cookies. */ @@ -64,7 +69,7 @@ public function body(): string public function json(?string $key = null, mixed $default = null): mixed { if (! $this->decoded) { - $this->decoded = json_decode($this->body(), true) ?? []; + $this->decoded = $this->decode($this->body()); } if (is_null($key)) { @@ -88,7 +93,34 @@ public function json(?string $key = null, mixed $default = null): mixed */ public function object(): array|object|null { - return json_decode($this->body(), false); + return $this->decode($this->body(), true); + } + + /** + * Set a custom decode callback. + * + * The callback will be invoked with the following parameters: + * - string $body: The raw response body. + * - bool $asObject: When true, the decoder should return an array of objects. + */ + public function decodeUsing(?Closure $callback): static + { + $this->decodeUsing = $callback; + $this->decoded = []; + + return $this; + } + + /** + * Decode the given response body. + */ + protected function decode(string $body, bool $asObject = false): array|object|null + { + if ($this->decodeUsing instanceof Closure) { + return ($this->decodeUsing)($body, $asObject); + } + + return json_decode($body, ! $asObject); } /** diff --git a/tests/HttpClient/HttpClientTest.php b/tests/HttpClient/HttpClientTest.php index 1b00eceb3..9849bef4d 100644 --- a/tests/HttpClient/HttpClientTest.php +++ b/tests/HttpClient/HttpClientTest.php @@ -430,6 +430,29 @@ public function testResponseCanBeReturnedAsFluent() $this->assertEquals(new Fluent([]), $response->fluent('missing_key')); } + public function testResponseDecodeUsingWithDifferentFormats() + { + $this->factory->fake([ + '*' => 'name:Taylor|framework:Laravel', + ]); + + $response = $this->factory->get('http://foo.com/api')->decodeUsing(function ($body) { + $parts = explode('|', $body); + $result = []; + + foreach ($parts as $part) { + [$key, $value] = explode(':', $part); + $result[$key] = $value; + } + + return $result; + }); + + $this->assertSame('Taylor', $response->json('name')); + $this->assertSame('Laravel', $response->json('framework')); + $this->assertIsArray($response->json()); + } + public function testSendRequestBodyAsJsonByDefault() { $body = '{"test":"phpunit"}';