简化 Laravel API 响应:禁用资源包装

144 阅读2分钟

使用 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 或与外部客户端合作,请确保清楚地记录此行为。