PHPackages                             gbradley/laravel-api-resource - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. gbradley/laravel-api-resource

ActiveLibrary[HTTP &amp; Networking](/categories/http)

gbradley/laravel-api-resource
=============================

Easier Laravel APIs

v1.8.0(11mo ago)116.9k↓50%MITPHPPHP &gt;=7.1.0

Since Dec 15Pushed 11mo ago1 watchersCompare

[ Source](https://github.com/gbradley/laravel-api-resource)[ Packagist](https://packagist.org/packages/gbradley/laravel-api-resource)[ Docs](https://github.com/gbradley/laravel-api-resource)[ RSS](/packages/gbradley-laravel-api-resource/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependenciesVersions (15)Used By (0)

This package expands on Laravel's base classes to provide a more succinct yet powerful way to control your API resources.

Goals
-----

[](#goals)

- Less code repetition; API resources take less time to write and maintain
- Improved relation handling including loading on-demand
- More control over data wrapping
- Won't affect your existing API by default

Requirements
------------

[](#requirements)

- Laravel 5.8+

Installation
------------

[](#installation)

```
$ composer require gbradley/laravel-api-resource

```

Usage
-----

[](#usage)

- [Extending the new resource class](#extending-the-new-resource-class)
- [Quicker attribute definitions](#quicker-attribute-definitions)
- [Relation handling](#relation-handling)
- [Contextual data](#contextual-data)
- [Data wrapping](#data-wrapping)

### Extending the new resource class

[](#extending-the-new-resource-class)

In your resource, instead of extending Laravel's `Resource`, change this to extend `GBradley\ApiResource\Resource` instead:

```
namespace App\Http\Resources;

use GBradley\ApiResource\Resource;

class PostResource extends Resource
{
	...
}

```

That's it! You can now use this resource as you would any normal resource. A main goal of this package is not to change resources' existing behaviour.

### Quicker attribute definitions

[](#quicker-attribute-definitions)

In our example resource, lets define some attributes. Normally you would have to do this individually, which can be quite verbose with a lot of repetition. Instead, you can now use `mergeAtrributes()` to quickly define the attributes you wish to use from your underlying model. This reduces something like:

```
class PostResource extends Resource
{

	public function toArray($request)
	{
		return [
			'id'		=> $this->id,
			'title'		=> $this->title,
			...
		];
	}

```

to this:

```
class PostResource extends Resource
{

	public function toArray($request)
	{
		return [
			$this->mergeAttributes('id', 'title', ...),
		];
	}

```

This has the additional benefit of retaining date formats in casted `date` or `datetime` attributes. Normally you would have to specify the format again in your resource, but this will now be handled for you.

Of course, you can mix both the new and old styles if needed:

```
class PostResource extends Resource
{

	public function toArray($request)
	{
		return [
			$this->mergeAttributes('id', 'title', ...),
			'dated'		=> $this->dated->format('d/m/Y'),
		];
	}

```

### Relation handling

[](#relation-handling)

Laravel's resources have two strategies for adding relations:

**Direct loading** - this always loads relations, often resulting in non-eager loaded queries being executed to generate data which the front-end may not need.

**Conditional loading** - this returns relations only when they are already loaded, deffering loading to the controller. However, your business logic may also load relations (for example inside an event handler), meaning your response structure can be affected by internal side-effects.

Instead, this package allows controllers to explicitly define which relations the resource *can* expose, with the resource determining which relations it *will* expose. These can either be *required* relations, which will always be exposed, or *optional* relations, which will be exposed if specified in the current request. The result is a flexible system which also utilises eager-loading.

To start, open your controller. Instead of instantiating a resource, or using the `collection()` method, use the static `build` method which can accept a model, a collection or a paginator instance:

```
return PostResource::build($model);

```

This exposes a fluid interface for specifying the relations. To specify relations which should always be exposed, pass an array of names to `withRelations()`:

```
return PostResource::build($model)
	->withRelations('blog', 'author');

```

Use `withOptionalRelations()` in the same manner to define relations which will only be exposed if found in the `load` parameter of the current request:

```
return PostResource::build($model)
	->withRelations('blog', 'author')
	->withOptionalRelations('comments.author');

```

As you can see from the above example, these methods also accept nested relations.

Now the controller has defined what it allows the resource to expose, you can configure the resource to do so using `mergeWhenExplicitlyLoaded()`. This method accepts the array of relation names that the resource can expose:

```
class PostResource extends Resource
{

	public function toArray($request)
	{
		return [
			$this->mergeAttributes('id', 'title'),
			$this->mergeWhenExplicitlyLoaded([
				'blog', 'author', 'comments'
			]),
		];
	}

```

#### Modifying related models

[](#modifying-related-models)

You may wish to modify models that have been loaded via these relations, before they are converted to their resource representations. You can do this by passing an associative array, with the relation name as the key and a closure as the value:

```
return PostResource::build($model)
    ->withRelations('blog', 'author')
    ->withOptionalRelations([
        'comments.author' => fn($author) => $author->append('avatar')
    ]);

```

#### Transforming relations

[](#transforming-relations)

When passing items sequentially, they will be exposed using the related object's `toArray` method. If you would like to transform them into other resources, pass the relation as the key and the desired resource class as the value. These techniques can be combined:

```
class PostResource extends Resource
{

	public function toArray($request)
	{
		return [
			$this->mergeAttributes('id', 'title'),
			$this->mergeWhenExplicitlyLoaded([
				'blog',
				'author',
				'comments' => CommentResource::class,
			]),
		];
	}

```

In this case, we can now also define `CommentResource` to expose its `author` relation when explicitly loaded.

```
class CommentResource extends Resource
{

	public function toArray($request)
	{
		return [
			$this->mergeAttributes('id', 'content'),
			$this->mergeWhenExplicitlyLoaded([
				'author',
			]),
		];
	}

```

This results in a request like this:

```
`GET /post/1?load[]=comments.author`

```

returning something like this:

```
{
	'id' : 1,
	'name' : 'Blog post 1',
	'blog'	: {
		'id' => 123,
		'title' => 'My Blog',
	},
	'author' : {
		'id' : 456,
		'name' : 'Graham',
	},
	'comments' : [
		{
			'id' : 789,
			'content' : 'Nice post!',
			'author' : {
				'id' : 987,
				'name' : 'Taylor Otwell'
			}
		}
	]
}

```

#### Polymorphic relations

[](#polymorphic-relations)

For polymirphic relations, first add a `{relation}_type` property to your resource. Then, specify a map of the possible classes and their relations inside `mergeWhenExplicitlyLoaded()`:

```
class CommentResource extends Resource
{

	public function toArray($request)
	{
		return [
			$this->mergeAttributes('id', 'content', 'commentable_type'),
			$this->mergeWhenExplicitlyLoaded([
				'author',
				'commentable' => [
				    Post::class => PostResource::class,
				    Page::class => PageResource::class,
				]
			]),
		];
	}

```

### Contextual data

[](#contextual-data)

Sometimes you may want to modify your resource's transformation based on information that isn't found in the request or the model being transformed.

To make arbitary data available to your resource, call `withContext()` on the resource builder returned from `build()`:

```
$context = [
	'foo' => [
		'bar' => 1
	]
];

return PostResource::build($model)
	->withRelations('blog')
	->withContext($context);

```

Your context data can be accessed inside the resource with `getContext()`. You can also use dot notation to retrive a subset of the data:

```
$data = $this->getContext('foo.bar');

```

You may use `mergeContext()` to merge all or part of the context into your representation:

```
class PostResource extends Resource
{

	public function toArray($request)
	{
		return [
			$this->mergeAttributes('id', 'title'),
			$this->mergeWhenExplicitlyLoaded([
				'blog' => BlogResource::class,
			]),
			$this->mergeContext('foo.bar')
		];
	}

```

Any context data provided to a resource will be passed down to any other resources loaded via relations. In the above example, the context data will be available on the instances of `BlogResource`.

### Data wrapping

[](#data-wrapping)

Laravel's resources allow you to disable data wrapping, however this does so for both models and collections. Although the security risks of returning top-level JSON arrays appear to have been resolved in all browers, some may prefer to avoid wrapping single models but retain wrapping for collections.

Do to this, call `withoutWrapping()` on the new Resource class, followed by `wrapCollection()`:

```
public function boot()
{
	Resource::withoutWrapping();
	Resource::wrapCollection('data');
}

```

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance51

Moderate activity, may be stable

Popularity27

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity60

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~153 days

Recently: every ~101 days

Total

14

Last Release

345d ago

Major Versions

v0.2 → v1.02020-03-02

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/116627?v=4)[Graham Bradley](/maintainers/gbradley)[@gbradley](https://github.com/gbradley)

---

Top Contributors

[![gbradley](https://avatars.githubusercontent.com/u/116627?v=4)](https://github.com/gbradley "gbradley (10 commits)")

---

Tags

apilaravelrest

### Embed Badge

![Health badge](/badges/gbradley-laravel-api-resource/health.svg)

```
[![Health](https://phpackages.com/badges/gbradley-laravel-api-resource/health.svg)](https://phpackages.com/packages/gbradley-laravel-api-resource)
```

###  Alternatives

[lomkit/laravel-rest-api

A package to build quick and robust rest api for the Laravel framework.

59152.2k](/packages/lomkit-laravel-rest-api)[api-platform/laravel

API Platform support for Laravel

59126.4k6](/packages/api-platform-laravel)[xtend-packages/rest-presenter

REST API Presenter &amp; Generator for Laravel

771.5k](/packages/xtend-packages-rest-presenter)[laragear/api-manager

Manage multiple REST servers to make requests in few lines and fluently.

161.8k](/packages/laragear-api-manager)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
