ronu / rest-generic-class
Base Class for generic restfull api in laravel
Requires
- php: ^8.2
- laravel/framework: ^12.61.1 || ^13.12.0
Requires (Dev)
- orchestra/testbench: ^10.9 || ^11.0
- phpunit/phpunit: ^11.5.50 || ^12.5.12
Suggests
- barryvdh/laravel-dompdf: Required for exportPdf()
- maatwebsite/excel: Required for exportExcel()
- ronu/rest-permissions: Route-based permissions: route catalog, channel authorization middleware, effective-permission Gate and Spatie models (moved out of this package in 3.0)
Provides
None
Conflicts
None
Replaces
None
- dev-main
- v3.0.0
- v2.9.0
- v2.8.2
- v2.8.1
- v2.8.0
- v2.7.1
- v2.7.0
- v2.6.0
- v2.5.0
- v2.4.2
- v2.4.1
- v2.4.0
- 2.3.3
- 2.3.2
- 2.3.1
- 2.3.0
- 2.2.4
- 2.2.3
- 2.2.2
- 2.2.1
- 2.2.0
- 2.1.9
- 2.1.8
- 2.1.7
- 2.1.6
- 2.1.5
- 2.1.4
- 2.1.3
- 2.1.2
- 2.1.1
- 2.1.0
- 2.0.9
- 2.0.8
- 2.0.7
- 2.0.6
- 2.0.5
- 2.0.4
- 2.0.3
- 2.0.2
- 2.0.1
- 2.0.0
- 1.9.9
- 1.9.8
- 1.9.7
- 1.9.6
- 1.9.5
- 1.9.4
- 1.9.3
- 1.9.2
- 1.9.1
- 1.9.0
- 1.8.9
- 1.8.8
- 1.8.6
- 1.8.5
- 1.8.4
- 1.8.3
- 1.8.2
- 1.8.1
- 1.8.0
- 1.7.9
- 1.7.8
- 1.7.5
- 1.7.4
- 1.7.2
- 1.7.1
- 1.7.0
- 1.6.9
- 1.6.8
- 1.6.7
- 1.6.6
- 1.6.5
- 1.6.2
- 1.6.1
- 1.6.0
- 1.5.9
- 1.5.8
- 1.5.7
- 1.5.6
- 1.5.3
- 1.5.2
- 1.5.1
- 1.5.0
- 1.4.9
- 1.4.8
- 1.4.7
- 1.4.5
- 1.4.4
- 1.4.3
- 1.4.2
- 1.4.1
- 1.4.0
- 1.3.9
- 1.3.8
- 1.3.7
- 1.3.6
- 1.3.5
- 1.3.4
- 1.3.3
- 1.3.2
- 1.3.1
- 1.3.0
- 1.2.9
- 1.2.8
- 1.2.7
- 1.2.6
- 1.2.5
- 1.2.4
- 1.2.3
- 1.2.1
- 1.2.0
- 1.1.12
- 1.1.11
- 1.1.10
- 1.1.9
- 1.1.8
- 1.1.7
- 1.1.6
- 1.1.5
- 1.1.4
- 1.1.3
- 1.1.2
- 1.1.1
- 1.0.9
- 1.0.8
- 1.0.5
- 1.0.4
- 1.0.3
- 1.0.2
- 1.0.1
- v1.0.0
- dev-feat/v3.0.0-extract-permissions
- dev-refactor/v2.9.0-authorization-contracts
- dev-fix/v2.8.1
- dev-feat/v2.8.0
- dev-fix/v2.7.1
- dev-fix/authorization-phase-2
- dev-feat/channel-scoped-authorization
- dev-fix/select-json-decode
- dev-feat/laravel-13-migration
- dev-claude/migrate-rest-generic-blaze-RmqKl
- dev-claude/analyze-cache-invalidation-pItqJ
- dev-claude/refactor-trait-duplication-rupv0
- dev-claude/reuse-library-function-izcpk
- dev-claude/add-database-validation-trait-PEIhd
- dev-claude/analyze-relationship-traits-0eI5Y
- dev-claude/pivot-data-support-Ip1SK
- dev-claude/add-trait-validation-59qLO
- dev-claude/fix-ids-validation-single-33VzQ
- dev-claude/add-conditions-to-db-rules-LNggS
- dev-claude/env-config-validation-trait-FXzqr
- dev-claude/document-laravel-12-advanced-xA7Dv
- dev-codex/analyze-cache-integration-options-for-library-a66gq3
- dev-codex/analyze-cache-integration-options-for-library
- dev-codex/reestructurar-y-documentar-en-espanol
- dev-codex/analyze-pdf-export-functionality
- dev-codex/audit-and-update-documentation-for-package
- dev-codex/auditar-proyecto-laravel-12-jdrm7d
- dev-codex/auditar-proyecto-laravel-12
- dev-codex/generate-laravel-library-documentation
- dev-claude/fix-parseconditionstring-type-I4yuI
- dev-claude/add-hierarchical-listing-e9h1v
- dev-claude/document-rest-api-queries-dYvtU
- dev-codex/analyze-library-for-improvements-and-defects-7xcakv
- dev-codex/analyze-library-for-improvements-and-defects-c7mvzd
- dev-codex/analyze-library-for-improvements-and-defects-40mzuo
- dev-codex/analyze-library-for-improvements-and-defects
This package is auto-updated.
Last update: 2026-10-18 22:47:24 UTC
README
A Laravel package that provides base classes for RESTful CRUD with dynamic filtering, relation loading, and hierarchical listing.
v3.0.0 — Route permissions moved to ronu/rest-permissions
The CRUD core no longer ships or depends on any permission code: the route permissions (catalog sync, SpatieAuthorize, the effective-permission Gate, readers, Spatie models, permission routes and the migration script) now live in ronu/rest-permissions, and Spatie is no longer a dependency of this package. The core authorizes through its contracts and Laravel's Gate. Upgrading: composer require ronu/rest-generic-class:^3.0 ronu/rest-permissions:^1.0; 2.x class names, the permissions config block and the route names keep working through the plugin. See the upgrade guide.
v2.9.0 — Authorization contracts
The CRUD core now authorizes eager loads and field writes only through Core\Contracts\Authorization (AuthorizationContext, RelationAuthorizer, FieldWriteAuthorizer) and Laravel's Gate, preparing the route permissions to move to their own package. No behaviour change with the default configuration; require_read without a request scope now fails closed. Also fixes SpatieRole::enabled_permissions() (PostgreSQL-only SQL, and an expired grant being honoured when another role held an active one). See the contracts and the release notes.
v2.8.2 — Direct user permissions without Spatie's trait
users:assign-permissions and the direct/role permission readers now work on user models without Spatie's HasPermissions/HasRoles (as generated applications are), and validation messages name the field instead of its value (an array value no longer answers 500). See the release notes.
v2.8.1 — Spatie 7/8 compatibility
SpatiePermission and SpatieRole failed to load with spatie/laravel-permission 7+ (e.g. Laravel 13.36 + Spatie 8.3.0 stopped artisan package:discover). findByName()/findOrCreate() now accept BackedEnum|string, so one release works with Spatie ^6.21 || ^7.0 || ^8.0 on Laravel 12 and 13. See the release notes.
v2.8.0 — Actions by ability and generic notation
Opt-in route attributes permission_ability / permission_requires collapse the routes of a relation into read/add/update/delete/manage actions that also require seeing the parent; grant them with admin.crm.clients.*-style patterns; the catalog syncs in batch (with --prune), and eager_relations=require_read authorizes ?relations=. See the public API, §10 and the release notes.
v2.7.1 — Fixes
GET /<channel>/modules no longer fails (with ?enabled= and the new ?format=uri), no PHP 8.4 implicit-nullable deprecations, and the channel authorization migration script now ships in scripts/.
v2.7.0 — Explicit global permissions
Opt-in explicit_globals (only routes marked with the permission_global action attribute are global; everything else fails closed), catalog_middleware to keep public routes out of the permission catalog, and the v2.5.0 legacy module-name fix. See the release notes.
v2.6.0 — Channel authorization
Optional channel prefixes, literal route permission names, fail-closed middleware, and an effective-permission Gate. Review the release notes and activation order before enabling authorization for channel-based applications.
Requirements
| Laravel | PHP | Test runtime |
|---|---|---|
| 12.61.1+ | 8.2+ | PHPUnit 11 |
| 13.12+ | 8.3+ | PHPUnit 12 |
No permission package is required. Route permissions (with spatie/laravel-permission) are provided by
ronu/rest-permissions. See requirements.
The package keeps Laravel 12 support while adding Laravel 13 support. See the detailed Spanish Laravel 13 migration guide for junior developers.
Installation
composer require ronu/rest-generic-class
Publish configuration (optional)
php artisan vendor:publish --tag=rest-generic-class-config
Quickstart
1) Model
<?php namespace App\Models; use Ronu\RestGenericClass\Core\Models\BaseModel; class Product extends BaseModel { protected $fillable = ['name', 'price', 'stock', 'category_id']; const MODEL = 'product'; const RELATIONS = ['category', 'reviews']; public function category() { return $this->belongsTo(Category::class); } public function reviews() { return $this->hasMany(Review::class); } }
2) Service
<?php namespace App\Services; use App\Models\Product; use Ronu\RestGenericClass\Core\Services\BaseService; class ProductService extends BaseService { public function __construct() { parent::__construct(Product::class); } }
3) Controller
<?php namespace App\Http\Controllers\Api; use App\Models\Product; use App\Services\ProductService; use Ronu\RestGenericClass\Core\Controllers\RestController; class ProductController extends RestController { protected $modelClass = Product::class; public function __construct(ProductService $service) { $this->service = $service; } }
4) Routes
use App\Http\Controllers\Api\ProductController; Route::prefix('v1')->group(function () { Route::apiResource('products', ProductController::class); Route::post('products/update-multiple', [ProductController::class, 'updateMultiple']); });
5) Query with filtering and relations
GET /api/v1/products?select=["id","name"]&relations=["category:id,name"]
{
"oper": {
"and": ["status|=|active", "price|>=|50"]
}
}
Parameter-driven aggregates
List endpoints support aggregate for global metrics and with_aggregates for
per-record relationship metrics (count, sum, avg, min, max). Models opt in
through HasRestAggregates. Execution uses native Laravel aggregate methods,
without accepting raw SQL. See aggregation parameters and examples
for authorization, filtering, pagination, cache behavior, and supported relations.
Configuration
Publish the config file and adjust values in config/rest-generic-class.php.
Environment variables:
LOG_LEVEL(default:debug)LOG_QUERY(default:false)REST_VALIDATE_COLUMNS(default:true)REST_STRICT_COLUMNS(default:true)REST_CACHE_ENABLED(default:false)REST_CACHE_STORE(default:CACHE_STORE; supportsredis,database,file,memcached, etc.)REST_CACHE_TTL(default:60seconds)REST_CACHE_TTL_LIST/REST_CACHE_TTL_ONEREST_VALIDATION_CACHE_ENABLED(default:true)REST_VALIDATION_CACHE_TTL(default:3600seconds)REST_VALIDATION_CACHE_PREFIX(default:validation)REST_VALIDATION_CONNECTION(default:db)
Cache strategy (Laravel native / Redis / database)
This package now supports generic cache integration via Laravel Cache stores.
How it works
- Cache is applied in
BaseServicefor read operations:list_allandget_one. - Cache key fingerprint includes: model, operation, route, query params, auth user, selected headers, normalized params, and a model cache version.
- Any successful write (
create,update,destroy,destroybyid) bumps a model-level cache version to avoid stale reads without needing tags. - Laravel 13's secure
cache.serializable_classes=falsedefault is honored: array payloads are cached, while paginator objects are not cached unless the host application supplies an explicit class allowlist. - Cache keys use the
rgc:v2namespace so incompatible Laravel 12 cache entries are not reused after an upgrade.
Store selection
Use any Laravel cache store by setting:
REST_CACHE_ENABLED=true REST_CACHE_STORE=redis # or: database, file, memcached, dynamodb, etc.
Request-aware behavior
You can control cache per request:
cache=falsedisables cache for that request.cache_ttl=120overrides TTL (seconds) for that request.
Example:
GET /api/v1/products?cache_ttl=120&select=["id","name"]
Multi-tenant / locale aware keys
By default cache varies by Accept-Language and X-Tenant-Id headers to avoid cross-tenant or cross-locale data leaks.
Common scenarios
1) Bulk update
POST /api/v1/products/update-multiple Content-Type: application/json { "product": [ {"id": 10, "stock": 50}, {"id": 11, "stock": 0} ] }
2) Hierarchy listing
{
"hierarchy": {
"filter_mode": "with_descendants",
"children_key": "children",
"max_depth": 3
}
}
3) Permission sync (Spatie, with ronu/rest-permissions)
POST /api/permissions/assign_roles Content-Type: application/json { "roles": ["admin"], "guard": "api", "mode": "SYNC", "perms": ["products.view", "products.create"] }
Edge scenarios
- Config caching hides env updates until you clear the config cache.
- Deep hierarchy trees can time out without
max_depth. - Excessive filter conditions trigger safety limits.
See Edge and extreme scenarios for detailed guidance.
API reference
Troubleshooting
Start with Troubleshooting for common errors such as invalid relations, operator errors, and missing optional packages.
Documentation
- Documentation index (EN)
- Documentation index (ES)
- Migración a Laravel 13 explicada para juniors
- Quickstart
- Configuration reference
- Scenarios
Contributing / Security
Please open issues and pull requests on GitHub. For security concerns, report them privately to the maintainer email listed in the package metadata.