Skip to content

Commit 53a9850

Browse files
[8.x] Add ability to customize json options on JsonResource response (#40208)
* Add ability to customize json options on JsonResource response * Add ability to customize json options on resource collections and paginated responses * formatting Co-authored-by: Taylor Otwell <[email protected]>
1 parent dd6ac5f commit 53a9850

File tree

6 files changed

+110
-2
lines changed

6 files changed

+110
-2
lines changed

src/Illuminate/Http/Resources/CollectsResources.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ class_exists($class = Str::replaceLast('Collection', 'Resource', get_class($this
5454
}
5555
}
5656

57+
/**
58+
* Get the JSON serialization options that should be applied to the resource response.
59+
*
60+
* @return int
61+
*/
62+
public function jsonOptions()
63+
{
64+
$collects = $this->collects();
65+
66+
return $collects ? (new $collects([]))->jsonOptions() : 0;
67+
}
68+
5769
/**
5870
* Get an iterator for the resource collection.
5971
*

src/Illuminate/Http/Resources/Json/JsonResource.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,16 @@ public function additional(array $data)
164164
return $this;
165165
}
166166

167+
/**
168+
* Get the JSON serialization options that should be applied to the resource response.
169+
*
170+
* @return int
171+
*/
172+
public function jsonOptions()
173+
{
174+
return 0;
175+
}
176+
167177
/**
168178
* Customize the response for a request.
169179
*

src/Illuminate/Http/Resources/Json/PaginatedResourceResponse.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ public function toResponse($request)
2323
$this->resource->additional
2424
)
2525
),
26-
$this->calculateStatus()
26+
$this->calculateStatus(),
27+
[],
28+
$this->resource->jsonOptions()
2729
), function ($response) use ($request) {
2830
$response->original = $this->resource->resource->map(function ($item) {
2931
return is_array($item) ? Arr::get($item, 'resource') : $item->resource;

src/Illuminate/Http/Resources/Json/ResourceResponse.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ public function toResponse($request)
4040
$this->resource->with($request),
4141
$this->resource->additional
4242
),
43-
$this->calculateStatus()
43+
$this->calculateStatus(),
44+
[],
45+
$this->resource->jsonOptions()
4446
), function ($response) use ($request) {
4547
$response->original = $this->resource->resource;
4648

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Illuminate\Tests\Integration\Http\Fixtures;
4+
5+
use Illuminate\Http\Resources\Json\JsonResource;
6+
7+
class PostResourceWithJsonOptions extends JsonResource
8+
{
9+
public function toArray($request)
10+
{
11+
return [
12+
'id' => $this->id,
13+
'title' => $this->title,
14+
'reading_time' => $this->reading_time,
15+
];
16+
}
17+
18+
public function jsonOptions()
19+
{
20+
return JSON_PRESERVE_ZERO_FRACTION;
21+
}
22+
}

tests/Integration/Http/ResourceTest.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Illuminate\Tests\Integration\Http\Fixtures\PostResource;
2525
use Illuminate\Tests\Integration\Http\Fixtures\PostResourceWithAnonymousResourceCollectionWithPaginationInformation;
2626
use Illuminate\Tests\Integration\Http\Fixtures\PostResourceWithExtraData;
27+
use Illuminate\Tests\Integration\Http\Fixtures\PostResourceWithJsonOptions;
2728
use Illuminate\Tests\Integration\Http\Fixtures\PostResourceWithOptionalAppendedAttributes;
2829
use Illuminate\Tests\Integration\Http\Fixtures\PostResourceWithOptionalData;
2930
use Illuminate\Tests\Integration\Http\Fixtures\PostResourceWithOptionalMerging;
@@ -495,6 +496,65 @@ public function testResourcesMayCustomizeExtraDataWhenBuildingResponse()
495496
]);
496497
}
497498

499+
public function testResourcesMayCustomizeJsonOptions()
500+
{
501+
Route::get('/', function () {
502+
return new PostResourceWithJsonOptions(new Post([
503+
'id' => 5,
504+
'title' => 'Test Title',
505+
'reading_time' => 3.0,
506+
]));
507+
});
508+
509+
$response = $this->withoutExceptionHandling()->get(
510+
'/', ['Accept' => 'application/json']
511+
);
512+
513+
$this->assertEquals(
514+
'{"data":{"id":5,"title":"Test Title","reading_time":3.0}}',
515+
$response->baseResponse->content()
516+
);
517+
}
518+
519+
public function testCollectionResourcesMayCustomizeJsonOptions()
520+
{
521+
Route::get('/', function () {
522+
return PostResourceWithJsonOptions::collection(collect([
523+
new Post(['id' => 5, 'title' => 'Test Title', 'reading_time' => 3.0]),
524+
]));
525+
});
526+
527+
$response = $this->withoutExceptionHandling()->get(
528+
'/', ['Accept' => 'application/json']
529+
);
530+
531+
$this->assertEquals(
532+
'{"data":[{"id":5,"title":"Test Title","reading_time":3.0}]}',
533+
$response->baseResponse->content()
534+
);
535+
}
536+
537+
public function testResourcesMayCustomizeJsonOptionsOnPaginatedResponse()
538+
{
539+
Route::get('/', function () {
540+
$paginator = new LengthAwarePaginator(
541+
collect([new Post(['id' => 5, 'title' => 'Test Title', 'reading_time' => 3.0])]),
542+
10, 15, 1
543+
);
544+
545+
return PostResourceWithJsonOptions::collection($paginator);
546+
});
547+
548+
$response = $this->withoutExceptionHandling()->get(
549+
'/', ['Accept' => 'application/json']
550+
);
551+
552+
$this->assertEquals(
553+
'{"data":[{"id":5,"title":"Test Title","reading_time":3.0}],"links":{"first":"\/?page=1","last":"\/?page=1","prev":null,"next":null},"meta":{"current_page":1,"from":1,"last_page":1,"links":[{"url":null,"label":"&laquo; Previous","active":false},{"url":"\/?page=1","label":"1","active":true},{"url":null,"label":"Next &raquo;","active":false}],"path":"\/","per_page":15,"to":1,"total":10}}',
554+
$response->baseResponse->content()
555+
);
556+
}
557+
498558
public function testCustomHeadersMayBeSetOnResponses()
499559
{
500560
Route::get('/', function () {

0 commit comments

Comments
 (0)