Core Concepts
This page explains the fundamental concepts and design patterns used throughout Rest Generic Class. Understanding these concepts will help you leverage the package’s full power.Service-Controller-Model Pattern
Rest Generic Class uses a three-layer architecture that separates concerns:Model Layer - Data Structure
Models extend
BaseModel and define:- Database structure (fillable, relations, casts)
- Business rules (validation, hierarchies)
- Security rules (allowed relations, field restrictions)
Service Layer - Business Logic
Services extend
BaseService and provide:- CRUD operations (create, read, update, delete)
- Query building (filtering, relations, pagination)
- Cache management (versioning, invalidation)
- Business workflows (bulk operations, exports)
Why This Pattern?
- Separation of Concerns: Each layer has a single responsibility
- Testability: Test business logic without HTTP concerns
- Reusability: Services can be called from controllers, commands, jobs, or other services
- Consistency: Same pattern across all resources in your application
Dynamic Filtering System
The filtering system uses anoper (operation) parameter that supports complex queries with nested relations.
Basic Filtering Syntax
Filters are expressed as condition strings in format:field|operator|value
Logical Operators
Combine conditions withand or or:
Nested Logical Operators
Build complex filter trees:Supported Operators
The package supports these operators (configurable in config):| Operator | Description | Example |
|---|---|---|
= | Equals | status|=|active |
!= | Not equals | status|!=|deleted |
> | Greater than | price|>|100 |
>= | Greater than or equal | price|>=|100 |
< | Less than | stock|<|10 |
<= | Less than or equal | stock|<=|10 |
like | SQL LIKE (case-sensitive) | name|like|%laptop% |
ilike | Case-insensitive LIKE | email|ilike|%@gmail.com |
in | In array | category_id|in|[1,2,3] |
not in | Not in array | status|not in|[deleted,archived] |
between | Between values | price|between|[100,500] |
null | Is NULL | deleted_at|null |
not null | Is not NULL | published_at|not null |
Operators are validated against an allowlist in the configuration. You can customize which operators are allowed via
config/rest-generic-class.php.Relation Filtering (whereHas)
Filter the main query based on related records:Nested Relation Filtering
Filter based on deeply nested relations using dot notation:Safety Limits
The filtering system enforces limits to prevent abuse:- Maximum depth: Nested filter depth is limited (default 5 levels)
- Maximum conditions: Total number of conditions is limited (default 100)
- Relation allowlists: Only declared relations can be filtered
- Operator allowlists: Only configured operators are allowed
Relation Loading
Eager loading is controlled via therelations parameter.
Basic Relation Loading
with() method.
Field Selection for Relations
Load only specific fields from related models:category:id,name will include category_id to ensure the relation works.
Nested Relations
Load relations of relations:Nested Relations with Field Selection
The “all” Shortcut
Load all declared relations:RELATIONS constant.
Nested Filtering (_nested parameter)
By default, relation filters (oper.relationName) affect the root query (SQL WHERE EXISTS). To also filter the loaded relation data, use _nested=true:
_nested=true:
- Root products are filtered to only those with reviews where rating >= 4 (WHERE EXISTS)
- Loaded reviews are also filtered to only show reviews with rating >= 4
_nested=true:
- Root products are filtered (WHERE EXISTS)
- But ALL reviews are loaded for those products
Hierarchical Data
Models can represent tree structures by defining a self-referencing foreign key.Enabling Hierarchy
Define the foreign key in your model:Hierarchical Listing
Request a tree structure with thehierarchy parameter:
Hierarchy Modes for show() Endpoint
| Mode | Description |
|---|---|
node_only | Just the requested node (no hierarchy) |
with_descendants | Node + all children/grandchildren |
with_ancestors | Chain from root down to this node |
full_branch | Root to node + all descendants |
Hierarchy Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
filter_mode | string | with_descendants | How to build the tree |
children_key | string | children | Key name for nested children |
max_depth | int|null | null | Maximum tree depth (null = unlimited) |
include_empty_children | bool | true | Include empty children arrays |
Caching Strategy
Rest Generic Class uses a version-based cache invalidation strategy that works with any Laravel cache backend.How It Works
Cache Key Generation
Each read operation generates a cache key based on:
- Model class
- Operation (list_all, get_one)
- Route and HTTP method
- All query parameters
- Current user ID
- Selected headers (tenant, locale)
- Model cache version
Cache Lookup
Before running a query, check if a cached result exists for this exact key.
- If found: Return cached data
- If not found: Execute query, cache result, return data
Why Version-Based Invalidation?
- Works with all cache stores (Redis, database, file, memcached) - doesn’t require tags
- Atomic invalidation - one version bump invalidates all cached queries for that model
- No cache pollution - old keys naturally expire, no need to track and delete them
- Multi-server safe - version is stored in shared cache, all servers see the change
Cache Configuration
Per-Request Cache Control
Clients can control caching behavior:Multi-Tenant Cache Safety
The cache key includes headers configured incache.vary.headers:
Role-Based Field Restrictions
Sensitive fields can be restricted to specific Spatie roles.Defining Field Restrictions
In your model, declare which roles can write which fields:/home/daytona/workspace/source/src/Core/Models/BaseModel.php:67-86
How It Works
- Fields NOT listed in any role are base fields - writable by anyone authenticated
- Fields listed under a role are privileged fields - writable only by users with that role
- Users with
is_superuser = truebypass all restrictions
- Regular users can write:
name,email - Admin users can write:
name,email,status,is_verified - Superusers can write: all fields
Enforcement Points
Field restrictions are enforced at two points:- FilterRequestByRole Middleware - Strips prohibited fields from the request payload
- BaseRequest Validation - Adds
prohibitedvalidation rules for denied fields
Field restrictions require
spatie/laravel-permission package. If not installed, the feature is inactive.Query Parameters Reference
Quick reference for all supported query parameters:| Parameter | Type | Description | Example |
|---|---|---|---|
select | array | Fields to select | ["id","name","price"] |
relations | array | Relations to load | ["category:id,name"] |
oper | object | Filter conditions | {"and":["status|=|active"]} |
orderby | array | Sorting | [{"price":"desc"}] |
pagination | object | Pagination config | {"page":1,"pageSize":25} |
_nested | boolean | Apply relation filters to loaded data | true |
hierarchy | object | Enable hierarchical listing | {"filter_mode":"with_descendants"} |
cache | boolean | Enable/disable cache | false |
cache_ttl | integer | Override cache TTL (seconds) | 120 |
attr / eq | object | Legacy equality filters | {"status":"active"} |
Next Steps
Now that you understand the core concepts, you’re ready to build your first REST API:Quick Start Guide
Follow the step-by-step guide to create a complete REST API in 5 minutes