brainstud/json-api-resource
JSON:API Resource for Laravel
Make your Laravel API JSON:API compliant with the Brainstud\JsonApi package.
Table of contents
- Installation
- Usage
- Relationships
- Resource depth
- Exception handler
- Example
- Deprecated
registermethod - Tweaking responses
- License
Installation
Require the package
composer require brainstud/json-api-resource
Usage
- Let your resource object extend from
JsonApiResourceinstead ofJsonResource. - Set the type of your resource as a string in
$this->type. - For each part of your resource, define the matching
to{resourcePart}method.
class Resource extends JsonApiResource
{
protected string $type = 'resources';
protected function toAttributes(Request $request): array
{
return [
'field' => $this->resource->field,
'other_field' => $this->resource->other_field,
];
}
protected function toRelationships(Request $request): array
{
return [
'relation' => ['relationMethod', Relation::class],
];
}
protected function toLinks(Request $request): array
{
return [
'type_of_link' => ['href' => 'link'],
];
}
protected function toMeta(Request $request): array
{
return [
'meta' => 'data',
];
}
}
Relationships
JSON:API: Includes
For the relationships to be included they need to be loaded. This can be done by implementing a ?include parameter or using spatie/laravel-query-builder.
Resource depth
The resource depth has a default of 2. This can be changed by passing an array to the resource where the second item is the required resource depth. In the following example we use a depth of 3:
public function show(ShowCourseRequest $request, Course $course)
{
$query = (new CoursesQueryBuilder)->find($course->id);
return new CourseResource([$query, 3]);
}
Which allows us to ask for an include nested 3 levels deep: /courses/{identifier}?include=content,content.answers,content.answers.feedback
Exception handler
This package contains an exception handler to render exceptions as JSON:API error messages.
Either use this handler directly by editing your app.php and registering this singleton
// app.php
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
\Brainstud\JsonApi\Handlers\JsonApiExceptionHandler::class
);
Or register your own exception handler and delegate the render to the JsonApiExceptionHandler::render method.
// app.php
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);
// handler.php
public function render($request, Throwable $exception)
{
if ($request->wantsJson()) {
return (new JsonApiExceptionHandler($this->container))->render($request, $exception);
}
return parent::render($request, $exception);
}
Return error response
There are multiple ways to return an error page
// Throw an exception that will be handled by the JsonApiExceptionHandler
throw new UnprocessableEntityHttpException();
// Return a defined error response
return (new UnprocessableEntityError)->response();
// Return a custom error response
return ErrorResponse::make(new DefaultError(
'PROCESSING_ERROR',
'Could not save item',
'An error occurred during saving of the item'
), Response::HTTP_INTERNAL_SERVER_ERROR);
Example usage
// Course.php
/**
* @property int $id
* @property string $title
* @property string $description
* @property Carbon $created_at
* @property Collection $enrollments
*/
class Course extends Model
{
protected $fillable = [
'title',
'description',
];
public function enrollments(): HasMany
{
return $this->hasMany(Enrollment::class);
}
}
// CourseResource.php
/**
* @property Course $resource
*/
class CourseResource extends JsonApiResource
{
protected string $type = 'courses';
protected function toAttributes(Request $request): array
{
return [
'title' => $this->resource->title,
'description' => $this->resource->description,
'created_at' => $this->resource->created_at->format('c'),
];
}
protected function toRelationships(Request $request): array
{
return [
'enrollments' => ['enrollments', EnrollmentResourceCollection::class],
];
}
protected function toLinks(Request $request): array
{
return [
'view' => ['href' => $this->resource->getShowUrl()],
];
}
protected function toMeta(Request $request): array
{
return [
'enrollments' => $this->resource->enrollments->count(),
];
}
}
// CoursesController.php
class CoursesController
{
public function index(IndexCoursesRequest $request)
{
$query = (new CoursesQueryBuilder)->jsonPaginate();
return new CourseResourceCollection($query);
}
public function show(ShowCourseRequest $request, Course $course)
{
$query = (new CoursesQueryBuilder)->find($course->id);
return new CourseResource($query);
}
}
Defining resources via the register method
In the previous version of the package, you would have to define the resource structure via a register method. This is still possible, but it is deprecated and will be removed in a later version.
To use this way of defining a resource, simply define a register method in your resource:
protected function register(): array
{
return [
'id' => $this->resource->identifier,
'type' => 'object_type',
'attributes' => [
'field' => $this->resource->field,
'other_field' => $this->resource->other_field,
],
'relationships' => [
'items' => ['items', ItemsResourceCollection::class],
'item' => ['item', ItemResource::class],
],
'meta' => [
'some_data' => 'some value',
],
'links' => [
'some_key' => 'some link',
],
];
}
Tweak response
The register method doesn't have access to $request like toArray of JsonResource has.
If you want to manipulate the response based on the request this can be done by overriding the addToResponse method.
protected function addToResponse($request, $response): array
{
if ($this->requestWantsMeta($request, 'data')
&& ($data = $this->getData())
) {
$response['meta']['data'] = $data;
}
return $response;
}
License
JsonApi is open-sourced software licensed under the MIT Licence
Related Packages
Powerful PHP database abstraction layer (DBAL) with many features for database s...
Laravel Serializable Closure provides an easy and secure way to serialize closur...
Cli error handling for console/command-line PHP applications.
Version History
| Version | Released | PHP | Laravel | License |
|---|---|---|---|---|
| v5.1.0 | ^8.5 | ^12.0 | | MIT | |
| v5.0.0 | ^8.5 | ^12.0 | MIT | |
| v4.3.3 | ^8.2 | ^8.0 | | MIT | |
| v4.3.1 | ^8.2 | ^8.0 | | MIT | |
| v4.3.0 | ^8.2 | ^8.0 | | MIT | |
| v4.2.0 | ^8.2 | ^8.0 | | MIT | |
| v4.1.1 | ^8.2 | ^8.0 | | MIT | |
| v4.1.0 | ^8.2 | ^8.0 | | MIT | |
| v4.0.6 | ^8.2 | ^8.0 | | MIT | |
| v4.0.5 | ^8.2 | ^8.0 | | MIT | |
| v4.0.4 | ^8.2 | ^8.0 | | MIT | |
| v4.0.3 | ^8.2 | ^8.0 | | MIT | |
| v4.0.2 | ^8.1 | ^8.0 | | MIT | |
| v4.0.1 | ^8.1 | ^8.0 | | MIT | |
| v4.0.0 | ^8.1 | ^8.0 | | MIT | |
| v3.1.11 | ^8.1 | ^8.0 | | MIT | |
| v3.1.10 | ^8.1 | ^8.0 | | MIT | |
| v3.1.9 | ^8.1 | ^8.0 | | MIT | |
| v3.1.8 | ^8.0 | ^8.0 | | MIT | |
| v3.1.7 | ^8.0 | ^8.0 | | MIT | |
| v3.1.6 | ^8.0 | ^8.0 | | MIT | |
| v3.1.5 | 8.0 | ^8.0 | | MIT | |
| v3.1.4 | ^7.4 | | ^8.0 | | MIT | |
| v3.1.3 | ^7.4 | | ^8.0 | | MIT | |
| v3.1.2 | ^7.4 | | ^8.0 | | MIT | |
| v3.1.1 | ^7.4 | | ^8.0 | MIT | |
| v3.1.0 | ^7.4 | | ^8.0 | MIT | |
| v3.0.1 | ^7.4 | | ^8.0 | | MIT | |
| v3.0.0 | ^7.4 | | ^8.0 | MIT | |
| v2.1.0 | ^7.4 | | ^8.0 | MIT |
Showing the latest 30 of 39. See every release on Packagist