Skip to content

Ark4ne/laravel-json-api

Repository files navigation

JsonApi - Laravel Resource

A Lightweight {JSON:API} Resource for Laravel.

Build Status codecov

Installation

composer require ark4ne/laravel-json-api

Usage

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

Resource

@see {json:api} resource-type

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')),
        ];
    }
}

toType

@see {json:api} resource-type

Returns resource type.

protected function toType(Request $request): string
{
    return 'user';
}

Default returns model class in kebab case : App\Models\MyPost => my-post

toIdentifier

@see {json:api} resource-identifier

Returns resource identifier.

protected function toIdentifier(Request $request): int|string
{
    return $this->id;
}

Default returns model id.

toAttributes

@see {json:api} resource-attributes

Returns resource attributes.

protected function toAttributes(Request $request): iterable
{
    return [
        'name' => $this->name,
        'email' => $this->email,
    ];
}

Laravel conditional attributes

@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',
        ]),
    ];
}

toRelationships

@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.

Laravel conditional relationships

@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')),
    ];
}

Relation links and meta

@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,
            ]),
    ];
}

toLinks

@see {json:api}: resource-linkage

Returns resource links.

protected function toLinks(Request $request): ?array
{
    return [
        'self' => route('api.user.show', ['id' => $this->id]),
    ];
}

toResourceMeta

@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),
    ];
}

toMeta

@see {json:api}: document-meta

Returns document meta.

protected function toMeta(Request $request): ?iterable
{
    return [
        "copyright": "Copyright 2022 My Awesome Api",
    ];
}

Collection

@see laravel: resource-collection

Collection are implemented in JsonApiCollection.

Usage is the same as laravel collections.

UserResource::collection(User::all()); // => JsonApiCollection