Dynamic API resources with mode-based field selection for Laravel. Define minimal, default, detailed modes and compose them on the fly.
benyaminrmb/laravel-dynamic-resources is a Laravel package for dynamic api resources with mode-based field selection for laravel. define minimal, default, detailed modes and compose them on the fly..
It currently has 1 GitHub stars and 52 downloads on Packagist (latest version v0.1.5).
Install it with composer require benyaminrmb/laravel-dynamic-resources.
Discover more Laravel packages by benyaminrmb
or browse all Laravel packages to compare alternatives.
Last updated
Dynamic API resources with mode-based field selection for Laravel. Define minimal, default, detailed modes and compose them on the fly. Reduce API payload sizes, improve performance, and give clients control over response structure.
minimal, default, detailed modes and switch between them->withAvatar()->withPosts()only() and except()?mode=minimal&fields=id,name#[Field] and #[Mode] attributesmake:dynamic-resource and resource:listcomposer require benyaminrmb/laravel-dynamic-resources
Publish the config (optional):
php artisan vendor:publish --tag=dynamic-resources-config
php artisan make:dynamic-resource UserResource --model=User
Or create manually:
<?php
namespace App\Http\Resources;
use Benyaminrmb\LaravelDynamicResources\DynamicResource;
class UserResource extends DynamicResource
{
public function fields(): array
{
return [
// Minimal mode - just IDs and names
'minimal' => [
'id',
'name',
],
// Default mode - standard fields
'default' => [
'id',
'name',
'email',
],
// Detailed mode - inherits default + adds more
'detailed' => fn() => [
...$this->mode('default'),
'bio' => $this->bio,
'created_at' => $this->created_at->toISOString(),
'posts' => PostResource::collection($this->whenLoaded('posts')),
],
// Composable modes - add these with withAvatar(), withPosts()
'avatar' => fn() => [
'avatar_url' => $this->avatar_url,
],
'posts' => fn() => [
'posts' => PostResource::collection($this->whenLoaded('posts')),
],
];
}
}
class UserController extends Controller
{
// Single resource with mode
public function show(User $user)
{
return UserResource::make($user)->detailed();
}
// Collection with mode
public function index()
{
return UserResource::collection(User::all())->minimal();
}
// Compose multiple modes
public function profile(User $user)
{
return UserResource::make($user)
->minimal()
->withAvatar()
->withPosts();
}
// Field filtering
public function summary(User $user)
{
return UserResource::make($user)
->default()
->only(['id', 'name', 'email']);
}
}
Modes are composable. You can combine them dynamically:
// Start with minimal, add avatar and posts
UserResource::make($user)
->minimal()
->withAvatar()
->withPosts();
// Remove a mode
UserResource::make($user)
->detailed()
->withoutPosts();
// Chain as many as you need
UserResource::make($user)
->minimal()
->withAvatar()
->withTimestamps()
->withoutTimestamps() // Changed our mind
->withPosts();
Fine-grained control over which fields appear:
// Include only these fields
UserResource::make($user)
->default()
->only(['id', 'name']);
// Exclude these fields
UserResource::make($user)
->detailed()
->except(['created_at', 'updated_at']);
Reference other modes to build upon them:
public function fields(): array
{
return [
'minimal' => ['id', 'name'],
'default' => fn() => [
...$this->mode('minimal'), // Include all minimal fields
'email',
],
'detailed' => fn() => [
...$this->mode('default'), // Include all default fields
'bio',
'created_at',
],
];
}
Use Laravel's conditional helpers:
public function fields(): array
{
return [
'default' => fn() => [
'id',
'name',
'avatar' => $this->when($this->avatar !== null, $this->avatar),
'posts_count' => $this->whenCounted('posts'),
'posts' => $this->whenLoaded('posts', fn() => PostResource::collection($this->posts)),
],
];
}
Collections inherit modes from the parent:
// All users will use minimal mode
UserResource::collection($users)->minimal();
// Compose modes on collections too
UserResource::collection($users)
->minimal()
->withAvatar();
// Field filtering on collections
UserResource::collection($users)
->default()
->only(['id', 'name']);
Enable the middleware to let clients control response structure:
// routes/api.php
Route::middleware('resource.fields')->group(function () {
Route::get('/users', [UserController::class, 'index']);
});
Now clients can use:
GET /api/users?mode=minimal
GET /api/users?fields=id,name,email
GET /api/users?mode=detailed&exclude=created_at
Add metadata to responses:
UserResource::make($user)
->minimal()
->additional([
'meta' => [
'version' => '2.0',
'generated_at' => now()->toISOString(),
],
]);
# Create a new dynamic resource
php artisan make:dynamic-resource UserResource --model=User
# List all dynamic resources and their modes
php artisan resource:list --modes
Publish and customize:
php artisan vendor:publish --tag=dynamic-resources-config
Key options in config/dynamic-resources.php:
return [
// Default mode when none specified
'default_mode' => 'default',
// Throw exceptions for undefined modes
'strict_mode' => env('DYNAMIC_RESOURCES_STRICT', false),
// Request-based field selection
'request_selection' => [
'enabled' => true,
'mode_parameter' => 'mode',
'fields_parameter' => 'fields',
'forbidden_modes' => ['admin', 'internal'],
],
];
If upgrading from v1, the main changes are:
ModularResource → DynamicResourceLaravelModularResourcesServiceProvider → DynamicResourceServiceProvider// v1
use Benyaminrmb\LaravelDynamicResources\ModularResource;
// v2
use Benyaminrmb\LaravelDynamicResources\DynamicResource;
composer test
composer analyse
composer format
Please see CONTRIBUTING for details.
If you discover any security-related issues, please email [email protected] instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.