bchalier / laravel-json-api
为Laravel提供的轻量级JSON:API资源
Requires
- php: ^8.1
- illuminate/collections: ^11.0
- illuminate/http: ^11.0
- illuminate/support: ^11.0
Requires (Dev)
- orchestra/testbench: ^9.0
- phpstan/phpstan: ^1.9.18
- phpunit/phpunit: ^9.5|^10.0
This package is auto-updated.
Last update: 2024-09-21 11:44:36 UTC
README
为Laravel提供轻量级的{JSON:API}资源。
安装
composer require ark4ne/laravel-json-api
配置
用法
此包是Laravel的JsonResource
类的特殊化。所有底层的API仍然存在,因此在你的控制器中,你仍然可以像使用基JsonResource
类一样与JsonApiResource
类交互
请求
此包允许通过“包含”参数动态包含在请求中请求的资源。
@see {json:api} fetching-includes
资源属性也将根据“字段”参数进行筛选。
@see {json:api} fetching-fields
您还可以非常简单地通过规则Rules\Includes
和Rules\Fields
验证给定资源的请求。
包含验证
use \Ark4ne\JsonApi\Requests\Rules\Includes; use \Illuminate\Foundation\Http\FormRequest; class UserFetchRequest extends FormRequest { public function rules() { return [ 'include' => [new Includes(UserResource::class)], ] } }
Rules\Includes
将验证include
与用户资源模式(由关系确定)完全匹配。
字段验证
use \Ark4ne\JsonApi\Requests\Rules\Fields; use \Illuminate\Foundation\Http\FormRequest; class UserFetchRequest extends FormRequest { public function rules() { return [ 'fields' => [new Fields(UserResource::class)], ] } }
Rules\Fields
将验证fields
与用户资源模式(由属性和关系确定)完全匹配。
自定义验证信息
资源
可实现的方法
protected function toType(Request $request): string; protected function toIdentifier(Request $request): int|string; protected function toAttributes(Request $request): iterable; protected function toRelationships(Request $request): iterable; protected function toResourceMeta(Request $request): ?iterable; protected function toMeta(Request $request): ?iterable;
示例
use Ark4ne\JsonApi\Resources\JsonApiResource; use Illuminate\Http\Request; class UserResource extends JsonApiResource { protected function toAttributes(Request $request): iterable { return [ 'name' => $this->name, 'email' => $this->email, ]; } protected function toResourceMeta(Request $request): ?iterable { return [ 'created_at' => $this->created_at->format(DateTimeInterface::ATOM), 'updated_at' => $this->updated_at->format(DateTimeInterface::ATOM), ]; } protected function toRelationships(Request $request): iterable { return [ 'posts' => PostResource::relationship(fn() => $this->posts, fn() => [ 'self' => "https://api.example.com/user/{$this->id}/relationships/posts", 'related' => "https://api.example.com/user/{$this->id}/posts", ]), 'comments' => CommentResource::relationship(fn() => $this->whenLoaded('comments')), ]; } }
toType
返回资源类型。
protected function toType(Request $request): string { return 'user'; }
默认返回模型类名,使用短横线命名法:App\Models\MyPost
=> my-post
toIdentifier
@see {json:api} resource-identifier
返回资源标识符。
protected function toIdentifier(Request $request): int|string { return $this->id; }
默认返回模型ID。
toAttributes
@see {json:api} resource-attributes
返回资源属性。
protected function toAttributes(Request $request): iterable { return [ 'name' => $this->name, 'email' => $this->email, ]; }
Laravel条件属性
@see laravel: eloquent-conditional-attributes
支持Laravel条件属性。
protected function toAttributes(Request $request): array { return [ 'name' => $this->name, 'email' => $this->email, // with lazy evaluation 'hash64' => fn() => base64_encode("{$this->id}-{$this->email}"), // Conditional attribute 'secret' => $this->when($request->user()->isAdmin(), 'secret-value'), // Merging Conditional Attributes // use applyWhen insteadof mergeWhen for keep fields // useful for fields request rules validation $this->applyWhen($request->user()->isAdmin(), [ 'first-secret' => 123, 'second-secret' => 456.789, ]), ]; }
描述属性
@see 描述符号
protected function toAttributes(Request $request): array { return [ 'name' => $this->string(), // pass key to describer $this->string('email'), // with lazy evaluation 'hash64' => $this->string(fn() => base64_encode("{$this->id}-{$this->email}")), // Conditional attribute $this->string('secret')->when($request->user()->isAdmin(), 'secret-value'), // Merging Conditional Attributes $this->applyWhen($request->user()->isAdmin(), [ 'first-secret' => $this->integer(fn() => 123), 'second-secret' => $this->float(fn() => 456.789), ]), ]; }
toRelationships
@see {json:api} resources-relationships
返回资源关系。
所有关系必须使用ModelResource::relationship
创建。这允许生成表示资源的模式,从而验证请求的包含项。
如果您的关联应该通过::collection(...)
方法创建的集合,您可以使用->asCollection()
。
如果您只想在请求包含中存在关联数据时加载数据,可以使用->whenIncluded()
方法。
protected function toRelationships(Request $request): array { return [ 'avatar' => AvatarResource::relationship($this->avatar), // with conditional relationship 'administrator' => $this->when($request->user()->isAdmin(), UserResource::relationship(fn() => $this->administrator), // as collection, with conditional value 'comments' => CommentResource::relationship(fn() => $this->whenLoaded('comments'))->asCollection(), // with relationship (allow to include links and meta on relation) 'posts' => PostResource::relationship(fn() => $this->posts)->withLinks(fn() => [ 'self' => "https://api.example.com/user/{$this->id}/relationships/posts", 'related' => "https://api.example.com/user/{$this->id}/posts", ])->asCollection(), ]; }
toRelationships
必须返回一个键为字符串的数组,键为JsonApiResource
或JsonApiCollection
。
Laravel条件关系
@see laravel: eloquent-conditional-relationships
支持Laravel条件关系。
protected function toRelationships(Request $request): array { return [ 'avatar' => AvatarResource::relationship($this->avatar), // as collection, with condition 'comments' => CommentResource::relationship(fn() => $this->whenLoaded('comments'))->asCollection(), // with relationship (allow to include links and meta on relation) 'posts' => PostResource::relationship(fn() => $this->posts) ->asCollection(), ]; }
描述属性
@see 描述符号
protected function toRelationships(Request $request): array { return [ 'avatar' => $this->one(AvatarResource::class), // custom relation name 'my-avatar' => $this->one(AvatarResource::class, 'avatar'), // as collection, with condition 'comments' => $this->many(CommentResource::class) ->whenLoaded(), // with relationship (allow to include links and meta on relation) 'posts' => $this->many(PostResource::class) ->links(fn() => [ 'self' => "https://api.example.com/posts/{$this->resource->id}/relationships/posts", 'related' => "https://api.example.com/posts/{$this->resource->id}/posts", ]) ->meta(fn() => [ 'total' => $this->integer(fn() => $this->resource->posts()->count()), ]), ]; }
关系链接和元数据
参见 {json:api}: 关联链接
参见 {json:api}: 关联元数据
返回关联的链接和元数据。
protected function toRelationships(Request $request): array { return [ 'posts' => PostResource::relationship(fn() => $this->posts)->withLinks(fn() => [ // links 'self' => "https://api.example.com/user/{$this->id}/relationships/posts", 'related' => "https://api.example.com/user/{$this->id}/posts", ])->withMeta(fn() => [ // meta 'creator' => $this->name, ]) ->asCollection(), ]; }
toLinks
返回资源链接。
protected function toLinks(Request $request): ?array { return [ 'self' => route('api.user.show', ['id' => $this->id]), ]; }
toResourceMeta
参见 {json:api}: 资源元数据
参见 {json:api}: 文档元数据
返回资源元数据。
protected function toResourceMeta(Request $request): ?iterable { return [ 'created_at' => $this->created_at->format(DateTimeInterface::ATOM), 'updated_at' => $this->updated_at->format(DateTimeInterface::ATOM), ]; }
toMeta
返回文档元数据。
protected function toMeta(Request $request): ?iterable { return [ "copyright": "Copyright 2022 My Awesome Api", ]; }
集合
集合在 JsonApiCollection
中实现。
用法与laravel集合相同。
UserResource::collection(User::all()); // => JsonApiCollection
描述性符号
值方法
关联方法
枚举
方法 enum
允许获取支持枚举的枚举值或单位枚举的名称。
根据结构
/// Role.php enum Role { case ADMIN; case USER; } /// State.php enum State:int { case ACTIVE = 1; case INACTIVE = 0; } /// User.php class User extends Model { $casts = [ 'role' => Role::class, 'state' => State::class, ]; }
以下资源属性
// UserResource.php protected function toAttributes(Request $request): array { return [ 'status' => $this->enum(), 'role' => $this->enum(), ]; }
将返回
[ "status": 1, "role": "ADMIN" ]