intermax/laravel-json-api

此包的最新版本(2.1.0)没有提供许可证信息。

可重用的过滤器、资源和其他API工具。

2.1.0 2024-09-19 20:54 UTC

README

Laravel API是一个根据JSON:API规范快速构建API的包。它还可以根据您的API端点动态生成OpenAPI文档。

安装

composer require intermax/laravel-json-api

配置

要按JSON:API格式渲染异常,可以将中间件Intermax\LaravelJsonApi\Middleware\RenderJsonApiExceptions添加到相应的路由中。一个合理的示例是在API中间件组中的HTTP Kernel中

// app/Http/Kernel.php

use Intermax\LaravelJsonApi\Middleware\RenderJsonApiExceptions;
...
    protected $middlewareGroups = [
        ...
    
        'api' => [
            ...
            RenderJsonApiExceptions::class,
        ],
    ];

基本用法

要创建端点,您只需创建一个Laravel路由,就像您通常所做的那样。之后,您需要创建一个资源。假设我们创建一个返回UserResource的端点

use Illuminate\Http\Request;
use Intermax\LaravelJsonApi\Resources\JsonApiResource;

class UserResource extends JsonApiResource
{
    public function getAttributes(Request $request): array
    {
        return [
            'email' => $this->resource->email,
            'name' => $this->resource->name,
        ];
    }
    
    public function getRelations(Request $request): ?array
    {
        return null;
    }
    
    public function getLinks(Request $request): ?array
    {
        return null;
    }
}

之后,您应该创建控制器方法。通常您会想要一个API资源控制器。如果您返回您刚刚创建的资源,您就使用Laravel API包创建了自己的第一个端点

use Illuminate\Http\Request;
use App\Http\Resources\UserResource;

class UserController
{
    public function show(User $user): UserResource
    {
        return new UserResource($user);
    }
}

提示:确保在控制器方法中对资源进行类型提示,以便可以正确生成Open API文档。有关更多信息,请参阅Open API生成

查询参数

您可能想要应用过滤器、排序和包含到请求中。在JSON:API中,这是通过将filtersort和include变量应用于查询字符串来完成的

/users?filter[isAdmin]=true&sort=name&include=team

CollectionRequest

使用此包,您可以配置一些预定义的过滤器或添加自己的过滤器。您还可以添加包含和排序。为此,您可以在控制器方法中添加一个CollectionRequest。这本质上是一个扩展的FormRequest。您的自定义CollectionRequest需要扩展Intermax\LaravelJsonApi\Requests\CollectionRequest。它可能看起来像这样

namespace App\Http\Requests;

use Intermax\LaravelJsonApi\Filters\ScopeFilter;
use Intermax\LaravelJsonApi\Filters\OperatorFilter;
use Intermax\LaravelJsonApi\Requests\CollectionRequest;
use Intermax\LaravelJsonApi\Sorts\Sort;
use Intermax\LaravelJsonApi\Includes\Relation;

class UserCollectionRequest extends CollectionRequest
{
    public function filters(): array
    {
        return [
            new OperatorFilter('createdAt'),
            new ScopeFilter('isAdmin'),
        ];
    }
    
    public function sorts(): array
    {
        return [
            new Sort('name'),
        ];
    }
    
    public function includes(): array
    {
        return [
            new Relation('team'), // Eloquent relation name
        ];
    }
}

此特定的CollectionRequest添加了两个过滤器,filter[createdAt]filter[isAdmin]。要了解这些特定过滤器的工作方式,请参阅过滤器类型

控制器

为了使过滤器、包含和排序真正发挥其魔法作用,我们还需要更多。在控制器中,需要使用QueryResolver来将过滤器应用于Eloquent查询。在底层,这使用了spatie的laravel-query-builder包。

use Intermax\LaravelJsonApi\Requests\QueryResolver;

class UserController
{
    public function index(UserCollectionRequest $request, QueryResolver $queryResolver): UserResourceCollection
    {
        $query = User::query();
        
        $queryResolver->resolve($request, $query);
        
        $query->where(...) // You can alter the query further if needed
        
        return new UserResourceCollection($query->jsonPaginate());
    }
}

过滤器类型

此包提供了两种内置过滤器。一种是ScopeFilter。正如其名称所暗示的,这将使用发送的值调用作用域。

第二种称为OperatorFilter。它允许您使用一组运算符进行查询

  • 等于:filter[column]=valuefilter[column][eq]=value
  • 不等于:filter[column][nq]=value
  • 大于:filter[column][gt]=value
  • 小于:filter[column][lt]=value
  • 大于等于:filter[column][gte]=value
  • 小于等于:filter[column][lte]=value
  • 包含:filter[column][contains]=value

可以指定允许的运算符(默认全部允许)

use Intermax\LaravelJsonApi\Filters\OperatorFilter

new OperatorFilter(
    fieldName: 'name',
    allowedOperators: [
        'eq',
        'nq',
        'contains',
    ], 
);

变异请求

对于POST、PUT或PATCH请求,此包提供了一个可扩展的基本请求以方便使用。您应该使用MutationRequest而不是Laravel中已知的常规FormRequest。此类帮助您遵守JSON:API规范进行请求

  • 它拒绝没有正确内容类型(application/vnd.api+json)的请求
  • 实现类可以为attributesrelationships字段提供规则
  • 它有用于检索validatedAttributesvalidatedRelationships的方法

⚠️ 警告:请注意,如果您之前没有检查内容类型,您可能会很容易地在您的应用程序中创建破坏性更改。

用法

一个示例实现可能看起来像这样

use Intermax\LaravelJsonApi\Requests\MutationRequest;

class UserUpdateRequest extends MutationRequest
{
    protected function type(): string
    {
        return 'users';
    }
    
    protected function attributeRules(): array
    {
        return [
            'email' => ['email'],
            'name' => ['string'],
        ]
    }
}

在控制器中,您可以使用这些方法来检索已验证的字段

public function update(UserUpdateRequest $request, User $user): UserResource
{
    $user->update($request->validatedAttributes());
    
    return new UserResource($user);
}

OpenAPI生成

此包利用Laravel Open API包提供/docs端点(以及/docs/json/docs/yaml端点)。

Open API包将扫描api路由,读取FormRequests,确定ApiResources并尝试猜测资源的输出。我们的目标是使用最少的配置生成尽可能多的文档。

为了使此功能最佳,需要满足一些条件

  • 对于'collection-type'端点,即使不使用Eloquent,也要使用CollectionRequest,它仍然能够推断查询参数。您甚至可以使用规则验证查询参数。
  • 在控制器方法中为要返回的资源指定类型提示。
  • 对于POST/PUT/PATCH端点,使用FormRequest验证,并包括其中的所有字段(即使它们没有验证)。包使用此信息来确定请求体。
  • 包将从资源数组中获取所有字段/属性。

改进资源属性数据类型

如果您查看文档并看到所有资源属性都在数组中以字符串形式列出,您还可以采取一项额外措施来改进它。将每个字段包装在Intermax\LaravelOpenApi\Generator\Values\Value类型对象中

use Intermax\LaravelOpenApi\Generator\Values\StringValue;
use Intermax\LaravelOpenApi\Generator\Values\IntegerValue;
use Intermax\LaravelOpenApi\Generator\Values\NumberValue;
use Intermax\LaravelOpenApi\Generator\Values\DateTimeValue;
use Intermax\LaravelOpenApi\Generator\Values\BooleanValue;
use Carbon\Carbon;
use Intermax\LaravelJsonApi\Resources\JsonApiResource;

class UserResource extends JsonApiResource
{
    public function getAttributes(Request $request): array
    {
        return [
            'age' => new IntegerValue(fn () => Carbon::now()->diffInYears($this->resource->birthDate)),
            'email' => new StringValue(fn () => $this->resource->email),
            'name' => new StringValue(fn () => $this->resource->name),
            'createdAt' => new DateTimeValue(fn () => $this->resource->created_at),
            'isAdmin' => new BooleanValue(fn () => $this->resource->is_admin),
        ];
    }
}