[Bug]: fields specified in `with` method of `Resource`s are not included in the generated spec
What happened?
Some resources may have defined a with method to include additional fields in responses:
https://laravel.com/docs/12.x/eloquent-resources#top-level-meta-data
The generated spec misses those fields. Is this intended?
How to reproduce the bug
<?php
namespace App\Http\Resources\V1;
use App\Models\Task;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
/**
* @mixin Task
*/
class TaskResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'user' => new UserResource($this->user),
'title' => $this->title,
'status' => $this->status,
'priority' => $this->priority,
/** @format date */
'due_date' => $this->due_date?->format('Y-m-d'),
'assignee' => new UserResource($this->assignee),
'tags' => TagResource::collection($this->tags),
];
}
/**
* @return array<string, mixed>
*/
public function with($request): array
{
return [
'data' => [
'description' => $this->description,
'created_at' => $this->created_at?->toRfc3339String(),
'updated_at' => $this->updated_at?->toRfc3339String(),
'metadata' => $this->metadata,
],
];
}
}
Package Version
0.12.34
PHP Version
8.4.12
Laravel Version
12.28.1
Which operating systems does with happen with?
macOS
Notes
No response
@elnurvl please show your controller as well
Closing the issue as it clearly works.
Feel free to reopen, but please make sure that you have the actual bug and you provide a way for me to reproduce. Make sure that the actual API endpoint return the data that Scramble does not document.
I am reopening the issue as it clearly does not work for me. I would at least like to know what I am doing wrong: if this is the case, please change the label, but I think it would deserve to be addressed as a documentation issue at that point.
app/Http/Controllers/V1/TaskController.php:
<?php
namespace App\Http\Controllers\V1;
use App\Http\Controllers\Controller;
use App\Http\Resources\V1\TaskResource;
use App\Models\Task;
use Illuminate\Support\Facades\Gate;
class TaskController extends Controller
{
/**
* Get the task in detail
*/
public function show(Task $task): TaskResource
{
return new TaskResource($task);
}
}
app/Http/Resources/V1/TaskResource:
<?php
namespace App\Http\Resources\V1;
use App\Models\Task;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
/**
* @mixin Task
*/
class TaskResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'user' => new UserResource($this->user),
'title' => $this->title,
'status' => $this->status,
'priority' => $this->priority,
/** @format date */
'due_date' => $this->whenNotNull($this->due_date?->format('Y-m-d'), null),
'assignee' => $this->whenNotNull(new UserResource($this->assignee), null),
/**
* Visible to admins only
*
* @format date-time
*/
'deleted_at' => $this->when(auth()->user()->is_admin ?? false, $this->deleted_at?->toRfc3339String()),
];
}
/**
* @return array<string, mixed>
*/
public function with($request): array
{
return [
'data' => [
'description' => $this->description,
/** @format date-time */
'created_at' => $this->created_at?->toRfc3339String(),
/** @format date-time */
'updated_at' => $this->whenNotNull($this->updated_at?->toRfc3339String(), null),
'metadata' => $this->metadata,
],
];
}
}
routes/api.php:
<?php
use App\Http\Controllers\V1\TaskController;
use Illuminate\Support\Facades\Route;
Route::prefix('v1')->group(function () {
Route::get('tasks/{task}', [TaskController::class, 'show']);
});
Turns out I do not have a permission to reopen the issue. 🥲
Thanks! Apparently the issue here is that you wrap your additional data in 'data' key and this confuses Scramble because that's the wrap key.
The easiest thing to do is to not wrap it in that key.
I'm still considering it as a bug, so reopened the issue
The resource schema documentation is correct though. Only toArray stuff is the part of the schema. top level additional data is applied only when the resource is the response itself
@romalytvynenko , additional data is specified with additional method of the resource and intended to be used from within specific controller actions and for that I agree it belongs to the response.
As for with, in my opinion, it is being defined inside the resource and conditioned by the resource making the fields part of that resource.
Basically, when you define fields in this method, those fields only appears with singular resource responses(GET@users/{user}) and omitted for list responses(GET@users). This makes it an especially useful feature if you want to define a light-weight variant of a resource for big lists without having to create a separate collection resource. The exclusive fields still become part of the resource, don't they?
@elnurvl the use case you have is nice indeed. It really is useful to have light/expanded variant of resources.
Speaking of with, here is what Laravel documentation says:
Sometimes you may wish to only include certain meta data with a resource response if the resource is the outermost resource being returned. Typically, this includes meta information about the response as a whole. To define this meta data, add a with method to your resource class.
Source: https://laravel.com/docs/12.x/eloquent-resources#top-level-meta-data
Based on this, whatever is in with is treated the same way as whatever you pass to additional. Well, like the framework itself treats it. Also, when you use the resource in some other resource, only the stuff from toArray will be in other resource's data.
So while it does make sense to include with as a part of schema in your specific case, I don't plan to make it a default behavior.