A Lightweight {JSON:API} Resource for Laravel.
composer require ark4ne/laravel-json-api
This package is an specialisation of Laravel's JsonResource
class.
All the underlying API's are still there, thus in your controller you can still interact
with JsonApiResource
classes as you would with the base JsonResource
class
Implementable methods :
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;
Example:
use Ark4ne\JsonApi\Resource\JsonApiCollection;
use Ark4ne\JsonApi\Resource\JsonApiResource;
use DateTimeInterface;
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' => fn() => PostResource::collection($this->posts)->asRelationship([
'self' => "https://api.example.com/user/{$this->id}/relationships/posts",
'related' => "https://api.example.com/user/{$this->id}/posts",
]),
'comments' => fn() => CommentResource::collection($this->whenLoaded('comments')),
];
}
}
Returns resource type.
protected function toType(Request $request): string
{
return 'user';
}
Default returns model class in kebab case : App\Models\MyPost
=> my-post
@see {json:api} resource-identifier
Returns resource identifier.
protected function toIdentifier(Request $request): int|string
{
return $this->id;
}
Default returns model id.
@see {json:api} resource-attributes
Returns resource attributes.
protected function toAttributes(Request $request): iterable
{
return [
'name' => $this->name,
'email' => $this->email,
];
}
@see laravel: eloquent-conditional-attributes
Support laravel conditional attributes.
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
$this->mergeWhen($request->user()->isAdmin(), [
'first-secret' => 'value',
'second-secret' => 'value',
]),
];
}
@see {json:api} resources-relationships
Returns resource relationships.
protected function toRelationships(Request $request): array
{
return [
'avatar' => AvatarResource::make($this->avatar),
// with lazy evaluation
'comments' => fn() => CommentResource::collection($this->whenLoaded('comments')),
// with relationship (allow to include links and meta on relation)
'posts' => fn() => PostResource::collection($this->posts)->asRelationship([
'self' => "https://api.example.com/user/{$this->id}/relationships/posts",
'related' => "https://api.example.com/user/{$this->id}/posts",
]),
];
}
toRelationships
must returns an array, keyed by string, of JsonApiResource
or JsonApiCollection
.
@see laravel: eloquent-conditional-relationships
Support laravel conditional relationships.
protected function toRelationships(Request $request): array
{
return [
'avatar' => AvatarResource::make($this->avatar),
// with lazy evaluation
'posts' => fn () => PostResource::collection($this->posts),
// with laravel conditional relationships
'comments' => fn() => CommentResource::collection($this->whenLoaded('comments')),
];
}
@see {json:api}: relation-linkage
@see {json:api}: relation-meta
Returns links and meta for a relation.
protected function toRelationships(Request $request): array
{
return [
'posts' => fn () => PostResource::collection($this->posts)->asRelationship([
// links
'self' => "https://api.example.com/user/{$this->id}/relationships/posts",
'related' => "https://api.example.com/user/{$this->id}/posts",
], [
// meta
'creator' => $this->name,
]),
];
}
Define with a Closure :
protected function toRelationships(Request $request): array
{
return [
'posts' => fn () => PostResource::collection($this->posts)->asRelationship(
// links
fn($collection) => [
'self' => "https://api.example.com/user/{$this->id}/relationships/posts",
'related' => "https://api.example.com/user/{$this->id}/posts",
],
// meta
fn($collection) => [
'creator' => $this->name,
]
),
];
}
Define with methods :
protected function toRelationships(Request $request): array
{
return [
'posts' => fn () => PostResource::collection($this->posts)
->asRelationship()
->withLinks([
'self' => "https://api.example.com/user/{$this->id}/relationships/posts",
'related' => "https://api.example.com/user/{$this->id}/posts",
])
->withMeta([
'creator' => $this->name,
]),
];
}
@see {json:api}: resource-linkage
Returns resource links.
protected function toLinks(Request $request): ?array
{
return [
'self' => route('api.user.show', ['id' => $this->id]),
];
}
@see {json:api}: resource-meta
@see {json:api}: document-meta
Returns resource meta.
protected function toResourceMeta(Request $request): ?iterable
{
return [
'created_at' => $this->created_at->format(DateTimeInterface::ATOM),
'updated_at' => $this->updated_at->format(DateTimeInterface::ATOM),
];
}
@see {json:api}: document-meta
Returns document meta.
protected function toMeta(Request $request): ?iterable
{
return [
"copyright": "Copyright 2022 My Awesome Api",
];
}
@see laravel: resource-collection
Collection are implemented in JsonApiCollection
.
Usage is the same as laravel collections.
UserResource::collection(User::all()); // => JsonApiCollection