Skip to main content

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:
1

Model Layer - Data Structure

Models extend BaseModel and define:
  • Database structure (fillable, relations, casts)
  • Business rules (validation, hierarchies)
  • Security rules (allowed relations, field restrictions)
Responsibility: What the data looks like and how it’s validated.
2

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)
Responsibility: How data is processed and retrieved.
3

Controller Layer - HTTP Interface

Controllers extend RestController and handle:
  • HTTP request/response lifecycle
  • Parameter parsing and normalization
  • Transaction boundaries
  • Error formatting
Responsibility: How clients interact via HTTP.

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 an oper (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 with and or or:

Nested Logical Operators

Build complex filter trees:

Supported Operators

The package supports these operators (configurable in config):
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:
This translates to SQL:

Nested Relation Filtering

Filter based on deeply nested relations using dot notation:
Relation filtering requires relations to be declared in the model’s RELATIONS constant for security. Undeclared relations will throw a 400 error.

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 the relations parameter.

Basic Relation Loading

This eager loads both relations using Laravel’s with() method.

Field Selection for Relations

Load only specific fields from related models:
Important: The package automatically includes foreign keys even if you don’t specify them. For example, 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:
This loads every relation in the model’s 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:
With _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
Without _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 the hierarchy parameter:
Response Structure:

Hierarchy Modes for show() Endpoint

Hierarchy Configuration Options

Unlimited depth (max_depth: null) on large trees can cause performance issues. Always set a reasonable limit in production.

Caching Strategy

Rest Generic Class uses a version-based cache invalidation strategy that works with any Laravel cache backend.

How It Works

1

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
2

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
3

Version Bump on Write

After any successful write operation (create, update, delete):
  • Increment the model’s cache version
  • All existing cached reads become invalid (because version changed)
  • Next reads will miss cache and regenerate with new version

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 in cache.vary.headers:
This ensures tenant A never sees cached data from tenant B.

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 = true bypass all restrictions
Example:
  • 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:
  1. FilterRequestByRole Middleware - Strips prohibited fields from the request payload
  2. BaseRequest Validation - Adds prohibited validation rules for denied fields
This dual enforcement provides defense in depth.
Field restrictions require spatie/laravel-permission package. If not installed, the feature is inactive.

Query Parameters Reference

Quick reference for all supported query parameters:

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