PHPackages                             jcfrane/laravel-resource-scope - 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. [API Development](/categories/api)
4. /
5. jcfrane/laravel-resource-scope

ActiveLibrary[API Development](/categories/api)

jcfrane/laravel-resource-scope
==============================

Symfony-like serialization scoping for Laravel API Resources. Define scopes to control which fields are returned per context.

v0.0.2(3mo ago)8638MITPHPPHP ^8.2CI passing

Since Feb 18Pushed 3mo agoCompare

[ Source](https://github.com/jcfrane/laravel-resource-scope)[ Packagist](https://packagist.org/packages/jcfrane/laravel-resource-scope)[ RSS](/packages/jcfrane-laravel-resource-scope/feed)WikiDiscussions main Synced 2d ago

READMEChangelog (2)Dependencies (8)Versions (3)Used By (0)

Laravel Resource Scope
======================

[](#laravel-resource-scope)

[![Tests](https://github.com/jcfrane/laravel-resource-scope/actions/workflows/tests.yml/badge.svg)](https://github.com/jcfrane/laravel-resource-scope/actions/workflows/tests.yml)[![Latest Stable Version](https://camo.githubusercontent.com/2e106fdab3c6fd79cb55e97c9418ae52efbef833d19df609c8817d694284da14/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6a636672616e652f6c61726176656c2d7265736f757263652d73636f70652e737667)](https://packagist.org/packages/jcfrane/laravel-resource-scope)[![License](https://camo.githubusercontent.com/4a06de5eb89d2da4ce173ac7c0066a499f7d4e17d040edf297916fa1fbabe092/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6a636672616e652f6c61726176656c2d7265736f757263652d73636f70652e737667)](https://packagist.org/packages/jcfrane/laravel-resource-scope)

Control which fields your Laravel API Resources return based on context. Define scopes like `listing`, `detail`, or `summary` and let the frontend request only the data it needs.

Inspired by Symfony's serialization groups.

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

[](#requirements)

- PHP 8.2+
- Laravel 11, 12, or 13

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

[](#installation)

```
composer require jcfrane/laravel-resource-scope
```

The package auto-discovers its service provider. No manual registration needed.

### Publish Config (Optional)

[](#publish-config-optional)

```
php artisan vendor:publish --tag=resource-scope-config
```

Quick Start
-----------

[](#quick-start)

### 1. Add the trait to your resource

[](#1-add-the-trait-to-your-resource)

```
use JCFrane\ResourceScope\Concerns\HasResourceScope;

class UserResource extends JsonResource
{
    use HasResourceScope;

    protected function scopeDefinitions(): array
    {
        return [
            'listing' => ['id', 'name', 'email', 'avatar'],
            'detail'  => ['id', 'name', 'email', 'avatar', 'bio', 'created_at', 'settings'],
        ];
    }

    public function toArray(Request $request): array
    {
        return $this->scoped([
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'avatar' => $this->avatar_url,
            'bio' => $this->bio,
            'created_at' => $this->created_at,
            'settings' => $this->whenLoaded('settings'),
        ]);
    }
}
```

### 2. Register the middleware

[](#2-register-the-middleware)

In `bootstrap/app.php`:

```
->withMiddleware(function (Middleware $middleware) {
    $middleware->api(append: [
        \JCFrane\ResourceScope\Middleware\SetResourceScope::class,
    ]);
})
```

Or apply it to specific route groups:

```
Route::middleware('resource.scope')->group(function () {
    Route::apiResource('users', UserController::class);
});
```

### 3. Request scoped data

[](#3-request-scoped-data)

```
# Listing — returns only id, name, email, avatar
GET /api/users?scope=listing

# Detail — returns all detail fields
GET /api/users/1?scope=detail

# No scope — returns everything (backwards compatible)
GET /api/users

```

You can also pass the scope via header:

```
X-Resource-Scope: listing

```

Defining Scopes
---------------

[](#defining-scopes)

### Method-based (recommended)

[](#method-based-recommended)

Define a `scopeDefinitions()` method that returns scope name =&gt; allowed field keys:

```
protected function scopeDefinitions(): array
{
    return [
        'listing' => ['id', 'name', 'email'],
        'detail'  => ['id', 'name', 'email', 'bio', 'skills', 'documents'],
    ];
}
```

### Attribute-based

[](#attribute-based)

Use PHP 8 attributes on the resource class:

```
use JCFrane\ResourceScope\Attributes\ResourceScope;

#[ResourceScope('listing', fields: ['id', 'name', 'email'])]
#[ResourceScope('detail', fields: ['id', 'name', 'email', 'bio', 'skills', 'documents'])]
class UserResource extends JsonResource
{
    use HasResourceScope;

    public function toArray(Request $request): array
    {
        return $this->scoped([
            // ...
        ]);
    }
}
```

If both are present, `scopeDefinitions()` takes priority.

Scope Cascading
---------------

[](#scope-cascading)

When a resource contains nested resources, you can control how scopes propagate. There are two ways to define mappings:

### Method-based mappings

[](#method-based-mappings)

```
class PostResource extends JsonResource
{
    use HasResourceScope;

    protected function scopeDefinitions(): array
    {
        return [
            'listing' => ['id', 'title', 'author', 'created_at'],
        ];
    }

    protected function scopeMappings(): array
    {
        return [
            'listing' => [
                UserResource::class => 'summary',
            ],
        ];
    }

    public function toArray(Request $request): array
    {
        return $this->scoped([
            'id' => $this->id,
            'title' => $this->title,
            'body' => $this->body,
            'author' => new UserResource($this->whenLoaded('author')),
            'created_at' => $this->created_at,
        ]);
    }
}
```

### Attribute-based mappings

[](#attribute-based-mappings)

You can also define mappings directly in the `#[ResourceScope]` attribute using the `mappings` parameter:

```
use JCFrane\ResourceScope\Attributes\ResourceScope;

#[ResourceScope('listing', fields: ['id', 'title', 'author', 'created_at'], mappings: [
    UserResource::class => 'summary',
])]
#[ResourceScope('detail', fields: ['id', 'title', 'body', 'author', 'created_at'])]
class PostResource extends JsonResource
{
    use HasResourceScope;

    public function toArray(Request $request): array
    {
        return $this->scoped([
            'id' => $this->id,
            'title' => $this->title,
            'body' => $this->body,
            'author' => new UserResource($this->whenLoaded('author')),
            'created_at' => $this->created_at,
        ]);
    }
}
```

When the `listing` scope is active on `PostResource`, the nested `UserResource` will automatically use the `summary` scope.

If both `scopeMappings()` method and attribute mappings are present, the method takes priority. If no mapping is defined, the parent's scope name passes through to nested resources. If the nested resource doesn't define that scope, it returns all fields.

Works with Laravel's Conditional Fields
---------------------------------------

[](#works-with-laravels-conditional-fields)

Scoping works alongside `whenLoaded()`, `whenHas()`, and `when()`. Both conditions apply — Laravel's conditional checks run first, then scoping filters the keys:

```
return $this->scoped([
    'id' => $this->id,
    'name' => $this->name,
    'documents' => DocumentResource::collection($this->whenLoaded('documents')),
    'is_admin' => $this->when($user->isAdmin(), true),
]);
```

Backwards Compatible
--------------------

[](#backwards-compatible)

- No scope parameter = all fields returned (existing behavior)
- Scope not defined on a resource = all fields returned
- Unknown scope name = all fields returned

No breaking changes to existing API responses.

Configuration
-------------

[](#configuration)

Published config file (`config/resource-scope.php`):

```
return [
    // Query parameter name (default: 'scope')
    'query_param' => 'scope',

    // HTTP header name (default: 'X-Resource-Scope')
    'header' => 'X-Resource-Scope',

    // Query param takes priority over header (default: true)
    'query_param_priority' => true,
];
```

Testing
-------

[](#testing)

```
composer test
```

License
-------

[](#license)

MIT

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance81

Actively maintained with recent releases

Popularity24

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

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 ~33 days

Total

2

Last Release

101d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/2dfbe5a9ae770e600c736bec7beef2ad46eca3cc19b3cb0a8de9816b615b8c96?d=identicon)[jcfrane](/maintainers/jcfrane)

---

Tags

apilaravelserializationresourcegroupsscope

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/jcfrane-laravel-resource-scope/health.svg)

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

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M345](/packages/psalm-plugin-laravel)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

816333.6k3](/packages/defstudio-telegraph)[api-platform/laravel

API Platform support for Laravel

58171.4k14](/packages/api-platform-laravel)[resend/resend-laravel

Resend for Laravel

1222.7M9](/packages/resend-resend-laravel)[essa/api-tool-kit

set of tools to build an api with laravel

53390.0k](/packages/essa-api-tool-kit)[simplestats-io/laravel-client

Server-side analytics for Laravel that follows the full funnel from visit to registration to payment, attributed to the channel that drove it. Revenue, MRR, churn and ad-spend profit (ROAS/CAC) per channel. GDPR compliant, ad-blocker proof.

5021.9k](/packages/simplestats-io-laravel-client)

PHPackages © 2026

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