使用 Laravel 构建 API 时,您经常使用 API 资源将模型转换为 JSON 响应。默认情况下,Laravel 将最外层的资源包装在数据键中。虽然这在许多情况下都很有用,但有时您可能希望响应结构更扁平。让我们探索如何禁用此包装并自定义 API 响应。
默认行为
通常,当您从 Laravel 路由返回资源或资源集合时,它会包装在数据密钥中。例如:
Route::get('/users', function () {
return UserResource::collection(User::all());
});
这可能会导致如下响应:
{
"data": [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
}
禁用换行
Laravel 提供了一种简单的方法来全局禁用此包装。您可以通过在基 JsonResource 类上调用 withoutWrapping 方法来执行此操作。这通常在服务提供商中完成。
以下是在 AppServiceProvider 中实现此功能的方法:
<?php
namespace App\Providers;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
JsonResource::withoutWrapping();
}
}
现在,您的 API 响应将不再包含数据包装器:
[
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
选择性包装
值得注意的是,withoutWrapping 方法只影响最外层的资源。如果您已手动将数据密钥添加到自己的资源集合中,则这些密钥将保持不变。
真实场景
考虑您正在为博客平台构建 API 的场景。您可能拥有帖子、评论和作者的资源。以下是在没有默认包装的情况下构建这些内容的方法:
class PostResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'content' => $this->content,
'author' => new AuthorResource($this->author),
'comments' => CommentResource::collection($this->comments),
];
}
}
class AuthorResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
];
}
}
class CommentResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'content' => $this->content,
'user' => $this->user->name,
];
}
}
禁用换行后,获取帖子的请求可能会返回:
{
"id": 1,
"title": "First Post",
"content": "This is the content of the first post.",
"author": {
"id": 1,
"name": "John Doe"
},
"comments": [
{
"id": 1,
"content": "Great post!",
"user": "Jane Smith"
},
{
"id": 2,
"content": "Thanks for sharing.",
"user": "Bob Johnson"
}
]
}
对于 API 使用者来说,这种更扁平的结构可以更直观、更容易使用。 虽然禁用包装可以带来更清晰、更扁平的 API 响应,但重要的是要考虑整个 API 的一致性。如果您正在构建公共 API 或与外部客户端合作,请确保清楚地记录此行为。