学习Laravel中的JSON API资源

188 阅读3分钟

在Laravel中构建API是我的激情所在, 我花了很多时间寻找完美的方式来返回一致的JSON:API友好的资源, 这样我就能找到并使用一个标准。

在过去, 我曾使用过一个拼凑的解决方案,刚好可以实现我所需要的,但这是相当大的工作量。这种方法的负面作用超过了它的好处,因为实现它所花费的开发时间只是感觉不值得。

对你我来说,幸运的是,Tim MacDonald为这个用例建立了一个奇妙的包。它允许我们建立并返回符合JSON:API标准的资源,而且很容易使用。让我们来看看这是如何工作的。

通常情况下,当建立一个API资源时,我们会根据我们想要实现的目标,扩展LaravelsJsonResourceCollectionResource 。我们的典型资源可能看起来像下面这样。

class PostResource extends JsonResource
{
    public function toArray($request): array
    {
        return [
            'id' => $this->id,
            'type' => 'post',
            'attributes' => [
                'title' => $this->title,
                'slug' => $this->slug,
                'content' => $this->content,
            ]
        ];
    }
}

我们正在添加一个简单的实现来 "伪造 "一个基本级别的JSON:API资源。但正如你所看到的,这有点--呸。让我们通过Tim来安装这个包。

composer require timacdonald/json-api

现在我们可以重构上述资源以遵循JSON:API标准。让我带你了解一下这些变化。

首先,我们需要把我们要扩展的类从JsonResource 改为JsonApiResource

class PostResource extends JsonApiResource

接下来,我们需要确保改变的是删除toArray 方法,因为这个包会为你处理这个问题--相反,我们使用不同的方法,对JSON:API标准有用。例如,要向你的资源添加attributes ,你可以使用以下方法。

protected function toAttributes(Request $request): array
{
    return [
        'title' => $this->title,
                'slug' => $this->slug,
                'content' => $this->content,
    ];
}

现在让我们来看看关系。以前我们会做类似的事情。

 return [
    'id' => $this->id,
    'type' => 'post',
    'attributes' => [
        'title' => $this->title,
        'slug' => $this->slug,
        'content' => $this->content,
    ],
    'relationships' => [
        'category' => new CategoryResource(
            resource: $this->whenLoaded('category'),
        ),
    ]
];

这绝不是一个糟糕的方法;然而,让我们看一下我们如何在JSON:API包上添加这些。

protected function toRelationships(Request $request): array
{
    return [
        'category' => fn () => new CategoryResource(
            resource: $this->category,
        ),
    ];
}

所以这一次,我们通过一个闭包来进行评估,以返回关系。这是一个非常强大的方法,因为它使我们能够为关系加载添加非常自定义的行为--这意味着我们可以加载不同的条件性关系或在资源上运行授权。另一点需要注意的是,只有当客户端包含了关系时,才会对闭合进行评估--这让它变得更干净。

再进一步说,为你的API资源添加链接是我觉得很重要的一步。添加这些链接可以使你的API具有导航性,允许客户根据需要以编程方式跟踪链接。以前,我将添加另一个数组条目来添加这些链接,并使用route 帮助器来呼出这些链接。JSON:API包有一个替代方法,特别流畅。

protected function toLinks(Request $request): array
{
    return [
        Link::self(route('api:v1:posts:show', $this->resource)),
    ];
}

正如你所看到的--它很流畅,很简单,并会为你生成正确的链接。当然,欢迎你在这里添加你需要的东西,但是它将以JSON:API的标准化方式添加链接--所以你不必这样做。

最后,元数据,在JSON:API中,你可以在meta-object ,所以你可以添加文档链接或任何你可能需要传递回来的API资源(取决于你的API设计)。这方面的用例并不多,但这个包确实支持它。因此,让我们看一看,以了解它。

protected function toMeta(Request $request): array
{
    return [
        'depreciated' => false,
        'docs' => 'https://docs.domain/com/resources/posts',
    ];
}

正如你在上面看到的,我们可以添加折旧警告,这样客户就可以得到他们需要考虑改变的资源的通知--以及一个解释替换方法的文档链接。