fallegahq/laravel-api-responder

A comprehensive Laravel package for building consistent API responses with DTOs, caching, and role-based visibility

Installs: 15

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/fallegahq/laravel-api-responder

v1.2.4 2025-12-26 02:13 UTC

This package is auto-updated.

Last update: 2025-12-26 02:15:38 UTC


README

A comprehensive Laravel package for building consistent, feature-rich API responses with DTOs, caching, role-based visibility, and more.

PHP Version Laravel Version License

Features

Core Features

  • ๐ŸŽฏ Consistent API Responses - Standardized JSON response structure
  • ๐Ÿ”„ DTO Transformation - Attribute-based data transformation with PHP 8.1+ attributes
  • ๐Ÿ” Role-Based Visibility - Control field visibility based on user roles
  • โšก Field-Level Caching - Cache expensive computed fields automatically
  • ๐Ÿ“Š Sparse Fieldsets - Support for ?fields=id,name query parameters
  • ๐Ÿ“„ Automatic Pagination - Built-in pagination support with metadata
  • ๐ŸŒ API Versioning - Header-based API versioning
  • ๐ŸŽจ Exception Handling - Unified exception handling for Laravel 10, 11, and 12
  • ๐Ÿ“ฆ Batch Operations - Process multiple API requests in a single call
  • ๐Ÿงช Testing Helpers - Fluent assertion helpers for API testing

Advanced Documentation Generation

  • ๐Ÿ“ OpenAPI 3.0 Generation - Auto-generate complete API documentation
  • ๐Ÿ”’ Authentication Awareness - Automatically detect and mark protected routes
  • ๐Ÿท๏ธ Smart Tagging & Grouping - Organize endpoints with custom tags and groups
  • ๐Ÿ“– Human-Friendly Descriptions - Document routes with intuitive attributes
  • ๐Ÿงช Test Coverage Validation - Verify documentation accuracy with test integration
  • ๐Ÿ” Query Parameter Documentation - Full validation rules (min, max, enum, format)
  • ๐Ÿ” Security Schemes - Bearer token authentication included automatically
  • ๐ŸŽฏ Enum Support - Auto-detects PHP enums and validation rules
  • ๐Ÿ”— Nested DTOs - Automatic relationship detection with $ref schemas
  • ๐Ÿ“Ž File Upload Documentation - Multipart/form-data with constraints
  • โš ๏ธ Deprecation Warnings - Mark deprecated endpoints in OpenAPI spec
  • ๐Ÿ” Route Filtering - Include/exclude routes from public documentation

Requirements

  • PHP 8.1, 8.2, or 8.3
  • Laravel 10.x, 11.x, or 12.x

Installation

Install via Composer:

composer require fallegahq/laravel-api-responder

The package will auto-register via Laravel's package discovery.

Publish Configuration

php artisan vendor:publish --tag=api-responder-config

This creates config/api-responder.php where you can customize all settings.

Quick Start

Laravel 12 Bootstrap Configuration

In your bootstrap/app.php:

<?php

use FallegaHQ\ApiResponder\Bootstrap\ApiExceptionHandler;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        api: __DIR__.'/../routes/api.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->api(
            prepend: [
                \FallegaHQ\ApiResponder\Http\Middleware\ApiResponderMiddleware::class,
            ]
        );
    })
    ->withExceptions(function (Exceptions $exceptions) {
        ApiExceptionHandler::configure($exceptions, [
            'dontFlash' => ['current_password', 'password', 'password_confirmation'],
            'dontReportDuplicates' => true,
        ]);
    })
    ->create();

Create a DTO

DTOs automatically include all model attributes. Define methods only for additional computed fields:

<?php

namespace App\DTOs;

use FallegaHQ\ApiResponder\DTO\BaseDTO;
use FallegaHQ\ApiResponder\DTO\Attributes\{ComputedField, Visible, Cached};

class UserDTO extends BaseDTO
{
    #[ComputedField(name: 'posts_count')]
    #[Cached(ttl: 3600)]
    public function postsCount(): int
    {
        return $this->source->posts()->count();
    }

    #[ComputedField(name: 'is_admin')]
    #[Visible(['admin', 'manager'])]
    public function isAdmin(): bool
    {
        return $this->source->role === 'admin';
    }

    #[ComputedField(name: 'full_name')]
    public function fullName(): string
    {
        return $this->source->first_name . ' ' . $this->source->last_name;
    }

    protected function getHiddenFields(): array
    {
        return ['password', 'remember_token'];
    }
}

Link DTO to Model

Use the #[UseDto] attribute on your model:

<?php

namespace App\Models;

use App\DTOs\UserDTO;
use FallegaHQ\ApiResponder\Attributes\UseDto;
use Illuminate\Database\Eloquent\Model;

#[UseDto(UserDTO::class)]
class User extends Model
{
    protected $fillable = ['name', 'email', 'password'];
    protected $hidden = ['password', 'remember_token'];

    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

Create a Controller

With #[UseDto] on the model, transformation happens automatically:

<?php

namespace App\Http\Controllers\Api;

use App\Models\User;
use FallegaHQ\ApiResponder\Http\Controllers\BaseApiController;
use Illuminate\Http\Request;

class UserController extends BaseApiController
{
    public function index()
    {
        $users = User::paginate(15);

        return $this->success($users, 'Users retrieved successfully');
    }

    public function show(User $user)
    {
        return $this->success($user);
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|email|unique:users',
        ]);

        $user = User::create($validated);

        return $this->created($user, 'User created successfully');
    }

    public function destroy(User $user)
    {
        $user->delete();
        return $this->noContent();
    }
}

Response Examples

Success Response

{
    "success": true,
    "message": "Users retrieved successfully",
    "data": [
        {
            "id": 1,
            "name": "John Doe",
            "email": "john@example.com",
            "created_at": "2024-12-22T10:00:00+00:00",
            "posts_count": 42,
            "is_admin": true,
            "full_name": "John Doe"
        }
    ],
    "meta": {
        "timestamp": "2024-12-22T22:00:00+00:00",
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "api_version": "v1",
        "execution_time": "45.23ms"
    }
}

Paginated Response

{
    "success": true,
    "data": [
        "..."
    ],
    "meta": {
        "current_page": 1,
        "last_page": 5,
        "per_page": 15,
        "total": 73,
        "from": 1,
        "to": 15
    },
    "links": {
        "first": "http://api.example.com/users?page=1",
        "last": "http://api.example.com/users?page=5",
        "prev": null,
        "next": "http://api.example.com/users?page=2"
    }
}

Error Response

{
    "success": false,
    "message": "Validation failed",
    "errors": {
        "email": ["The email field is required."],
        "password": ["The password must be at least 8 characters."]
    },
    "meta": {
        "timestamp": "2024-12-22T22:00:00+00:00",
        "request_id": "550e8400-e29b-41d4-a716-446655440000"
    }
}

Key Features

Sparse Fieldsets

Request only the fields you need:

# Only return id and name
GET /api/users?fields=id,name

# Exclude sensitive fields
GET /api/users?exclude=email,role

# Include relationships
GET /api/users?include=posts,comments

Role-Based Visibility

Control field visibility based on user roles:

#[ComputedField(name: 'sensitive_data')]
#[Visible(['admin', 'manager'])]
public function sensitiveData(): string
{
    return $this->source->internal_data;
}

Field-Level Caching

Cache expensive computations:

#[ComputedField(name: 'statistics')]
#[Cached(ttl: 3600, key: 'user_stats')]
public function statistics(): array
{
    return [
        'posts' => $this->source->posts()->count(),
        'followers' => $this->source->followers()->count(),
    ];
}

API Versioning

Version your API responses:

#[ComputedField(name: 'new_field')]
#[Versioned(['v2'])]
public function newField(): string
{
    return 'Only visible in v2';
}

Request with header:

curl -H "X-API-Version: v2" https://api.example.com/users

Testing

Use fluent assertion helpers:

use Tests\TestCase;
use FallegaHQ\ApiResponder\Tests\AssertableApiResponse;
use Illuminate\Foundation\Testing\RefreshDatabase;

class UserControllerTest extends TestCase
{
    use RefreshDatabase;

    public function test_index_returns_users()
    {
        User::factory()->count(3)->create();

        $response = $this->getJson('/api/users');

        $response->assertStatus(200)
            ->assertJsonStructure([
                'success',
                'message',
                'data' => [['id', 'name', 'email', 'posts_count']],
                'meta'
            ]);
    }

    public function test_show_returns_single_user()
    {
        $user = User::factory()->create(['name' => 'John Doe']);

        $response = $this->getJson("/api/users/{$user->id}");

        $response->assertStatus(200)
            ->assertJson([
                'success' => true,
                'data' => [
                    'id' => $user->id,
                    'name' => 'John Doe',
                ]
            ]);
    }
}

Documentation Attributes Reference

The package provides powerful attributes for documenting your API endpoints:

Attribute Target Purpose Parameters
#[ApiDescription] Method Custom summary and description summary, description
#[ApiRequiresAuth] Method/Class Mark endpoint as requiring authentication requiresAuth (default: true)
#[ApiParam] Method Query parameter documentation name, type, description, required, example, minimum, maximum, enum, format
#[ApiTag] Class/Method Categorize endpoints tags (string or array)
#[ApiGroup] Class/Method Group with description name, description, priority
#[ApiRequest] Method Request body schema fields, description, dto
#[ApiResponse] Method Response schema model, type, description, statusCodes
#[UseDto] Class Link DTO to model dtoClass
#[ApiDeprecated] Method/Class Mark as deprecated reason, since, replacedBy
#[ApiFileUpload] Method Document file uploads name, description, required, allowedMimeTypes, maxSizeKb, multiple
#[ApiHidden] Method/Class Hide from documentation reason
#[ApiEnum] Property/Parameter Document enum values values, description

Attribute Examples

#[ApiDescription] - Endpoint Documentation

#[ApiDescription(
    summary: 'Create new post',
    description: 'Creates a new blog post with validation'
)]
public function store(Request $request) { }

#[ApiRequiresAuth] - Manual Authentication Marking

// Authentication is auto-detected from middleware (auth, auth:sanctum, etc.)
// Use this attribute only when you need to manually override detection

// On a specific method
#[ApiRequiresAuth]
public function sensitiveOperation() { }

// On entire controller (all methods require auth)
#[ApiRequiresAuth]
class AdminController extends BaseApiController { }

// Explicitly mark as NOT requiring auth (override middleware detection)
#[ApiRequiresAuth(requiresAuth: false)]
public function publicEndpoint() { }

#[ApiParam] - Query Parameters (Repeatable)

#[ApiParam('page', 'integer', 'Page number', required: false, example: 1, minimum: 1)]
#[ApiParam('per_page', 'integer', 'Items per page', minimum: 1, maximum: 100)]
#[ApiParam('status', 'string', 'Filter by status', enum: ['active', 'inactive'])]
#[ApiParam('search', 'string', 'Search term', required: false)]
public function index() { }

#[ApiTag] - Categorization

// Class-level (applies to all methods)
#[ApiTag(['Users', 'Management'])]
class UserController extends BaseApiController { }

// Method-level (additional tags)
#[ApiTag('Auth')]
public function login() { }

#[ApiGroup] - Grouping with Description

#[ApiGroup(
    name: 'User Management',
    description: 'Endpoints for managing user accounts and profiles',
    priority: 1  // Controls display order
)]
class UserController extends BaseApiController { }

#[ApiDeprecated] - Deprecation Warnings

#[ApiDeprecated(
    reason: 'Use the new v2 endpoint instead',
    since: 'v2.0',
    replacedBy: 'newEndpoint'
)]
public function oldEndpoint() { }

#[ApiFileUpload] - File Upload Documentation

#[ApiFileUpload(
    name: 'avatar',
    description: 'User profile picture',
    required: true,
    allowedMimeTypes: ['image/jpeg', 'image/png'],
    maxSizeKb: 2048,
    multiple: false
)]
public function uploadAvatar(Request $request) { }

#[ApiHidden] - Hide Routes from Documentation

// Hide entire controller
#[ApiHidden(reason: 'Internal API')]
class InternalController extends BaseApiController { }

// Or hide specific method
#[ApiHidden]
public function debugEndpoint() { }

#[ApiEnum] - Document Enum Values

use App\Enums\UserRole;

// Enum values are auto-detected from:
// 1. PHP 8.1+ enums with model casts
class User extends Model {
    protected function casts(): array {
        return [
            'role' => UserRole::class, // Auto-detected!
        ];
    }
}

// 2. Validation rules
#[ApiRequest(fields: [
    'status' => [
        'type' => 'string',
        'validation' => 'required|in:active,inactive,pending', // Auto-detected!
    ],
])]

// 3. Explicit enum arrays
#[ApiParam('role', 'string', 'User role', enum: ['admin', 'user', 'moderator'])]
#[ApiRequest(fields: [
    'role' => [
        'type' => 'string',
        'enum' => ['admin', 'user', 'moderator'], // Explicit
    ],
])]

Authentication Detection

The package automatically detects protected routes from middleware and marks them with the security field in OpenAPI documentation.

Automatic Detection

Routes are automatically detected as requiring authentication if they use any of the configured auth middleware:

// These routes are automatically marked as protected
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/users', [UserController::class, 'index']);
    Route::post('/posts', [PostController::class, 'store']);
});

Configure Auth Middleware

Customize which middleware names indicate authentication in config/api-responder.php:

'documentation' => [
    'auth_middleware' => [
        'auth',
        'auth:api',
        'auth:sanctum',
        'auth.basic',
        'can',
        'custom-auth', // Add your custom auth middleware
    ],
],

Manual Override

Use #[ApiRequiresAuth] to manually mark endpoints when automatic detection isn't sufficient:

// Force authentication requirement
#[ApiRequiresAuth]
public function sensitiveOperation() { }

// Explicitly mark as public (override middleware detection)
#[ApiRequiresAuth(requiresAuth: false)]
public function publicEndpoint() { }

Enum Support

The package automatically detects and documents enum values from multiple sources.

PHP 8.1+ Enums

Create a backed enum:

namespace App\Enums;

enum UserRole: string {
    case ADMIN = 'admin';
    case USER = 'user';
    case MODERATOR = 'moderator';
}

Use it in your model:

use App\Enums\UserRole;

#[UseDto(UserDTO::class)]
class User extends Model {
    protected function casts(): array {
        return [
            'role' => UserRole::class, // Automatically detected!
        ];
    }
}

Handle in your DTO:

class UserDTO extends BaseDTO {
    #[ComputedField(name: 'role')]
    public function role(): string {
        return $this->source->role?->value ?? UserRole::USER->value;
    }
    
    #[ComputedField(name: 'is_admin')]
    public function isAdmin(): bool {
        return $this->source->role === UserRole::ADMIN;
    }
}

Enum Detection in Documentation

Enums are automatically detected from:

  1. Model Casts - PHP enums in $casts array
  2. Validation Rules - in:value1,value2 rules
  3. Explicit Arrays - enum parameter in attributes

All enum values appear as dropdowns in Swagger UI and Postman!

Nested DTOs and Relationships

The package automatically detects and includes Eloquent relationships in your API responses when using DTOs.

Automatic Relationship Detection

Simply add #[UseDto] to your models and eager load relationships:

#[UseDto(UserDTO::class)]
class User extends Model {
    public function posts(): HasMany {
        return $this->hasMany(Post::class);
    }
}

#[UseDto(PostDTO::class)]
class Post extends Model {
    public function author(): BelongsTo {
        return $this->belongsTo(User::class);
    }
}

// In your controller
public function show(User $user) {
    // Eager load the relationship
    $user->load('posts');
    
    // DTO automatically includes nested posts
    return $this->success($user);
}

Configuration

'nested_dtos' => [
    // Automatically detect and include nested DTOs from relationships
    'auto_detect_relationships' => true,
    
    // Include relationships even if not loaded (NOT RECOMMENDED - causes N+1)
    'include_unloaded_relationships' => false,
    
    // Maximum depth for nested DTO resolution (prevents infinite loops)
    'max_nesting_depth' => 3,
],

โš ๏ธ Important: Always eager load relationships to avoid N+1 query problems:

// โœ… Good - Eager loaded
$users = User::with(['posts', 'posts.comments'])->get();

// โŒ Bad - Lazy loaded (causes N+1)
$users = User::all(); // Don't do this if you need relationships

OpenAPI Documentation

Nested DTOs are automatically documented with proper $ref references:

{
  "UserDTO": {
    "type": "object",
    "properties": {
      "posts": {
        "type": "array",
        "items": { "$ref": "#/components/schemas/PostDTO" },
        "description": "Related PostDTO collection (only included when loaded)"
      }
    }
  }
}

Documentation

OpenAPI Documentation Generation

The package can automatically generate OpenAPI 3.0 documentation from your routes, DTOs, and attributes with advanced features:

  • Authentication Awareness - Automatically detects and marks protected routes
  • Smart Grouping & Tagging - Organizes endpoints by category with custom tags
  • Human-Friendly Descriptions - Document routes with intuitive attributes
  • Testing Integration - Validates documentation accuracy and test coverage
  • Enum Support - Auto-detects enums from validation rules and PHP enums
  • Nested DTOs - Automatically includes relationships with proper $ref schemas
  • File Uploads - Documents multipart/form-data with file constraints
  • Deprecation Warnings - Marks deprecated endpoints in OpenAPI spec
  • Route Filtering - Include/exclude routes from public documentation

Generate Documentation

# Generate to default location (api-docs.json)
php artisan api:generate-docs

# Custom output file
php artisan api:generate-docs --output=openapi.json

# Validate test coverage
php artisan api:generate-docs --validate-tests

# Show warnings for missing tests
php artisan api:generate-docs --validate-tests --show-warnings

# Filter routes (include/exclude patterns)
php artisan api:generate-docs --include="api/public/*" --exclude="api/internal/*"

# Filter by controllers
php artisan api:generate-docs --include-controllers="*UserController" --exclude-controllers="*InternalController"

Document Your API with Attributes

Use attributes to enrich your generated documentation:

use FallegaHQ\ApiResponder\Attributes\{
    ApiDescription, ApiParam, ApiTag, ApiGroup,
    ApiRequest, ApiResponse, UseDto
};

#[UseDto(UserDTO::class)]
class User extends Model
{
    // Model definition
}

#[ApiTag(['Users', 'Management'])]
#[ApiGroup('Users', 'User management and profile operations')]
class UserController extends BaseApiController
{
    #[ApiDescription(
        summary: 'List all users',
        description: 'Retrieves a paginated list of all users in the system',
        requiresAuth: true
    )]
    #[ApiParam('page', 'integer', 'Page number', required: false, example: 1)]
    #[ApiParam('per_page', 'integer', 'Items per page', required: false, minimum: 1, maximum: 100)]
    #[ApiParam('search', 'string', 'Search by name or email', required: false)]
    #[ApiResponse(
        model: User::class,
        type: 'paginated',
        description: 'Returns paginated list of users'
    )]
    public function index()
    {
        return $this->success(User::paginate());
    }

    #[ApiDescription(
        summary: 'Get user details',
        description: 'Retrieves detailed information about a specific user',
        requiresAuth: true
    )]
    #[ApiResponse(
        model: User::class,
        type: 'single',
        description: 'Returns a single user with full details'
    )]
    public function show(User $user)
    {
        return $this->success($user);
    }

    #[ApiDescription(
        summary: 'Create new user',
        description: 'Creates a new user account with the provided information'
    )]
    #[ApiRequest(
        fields: [
            'name' => ['type' => 'string', 'description' => 'User name', 'example' => 'John Doe'],
            'email' => ['type' => 'string', 'format' => 'email', 'description' => 'User email'],
            'password' => ['type' => 'string', 'format' => 'password', 'minimum' => 8]
        ],
        description: 'Create a new user'
    )]
    #[ApiResponse(model: User::class, type: 'single')]
    #[ApiTag('Auth')]
    public function store(Request $request)
    {
        // Implementation
    }
}

Available Documentation Attributes

#[ApiDescription]

Provides human-friendly summary and description for endpoints:

#[ApiDescription(
    summary: 'Short summary of the endpoint',
    description: 'Detailed description with markdown support',
    requiresAuth: true  // Marks endpoint as protected
)]

#[ApiParam]

Documents query parameters (repeatable):

#[ApiParam(
    name: 'filter',
    type: 'string',
    description: 'Filter results',
    required: false,
    example: 'active',
    enum: ['active', 'inactive', 'pending']
)]
#[ApiParam('page', 'integer', 'Page number', minimum: 1)]

#[ApiTag]

Organizes endpoints into categories (repeatable, can be used on class or method):

#[ApiTag('Users')]  // Single tag
#[ApiTag(['Users', 'Admin'])]  // Multiple tags

#[ApiGroup]

Groups related endpoints with descriptions (can be used on class or method):

#[ApiGroup(
    name: 'User Management',
    description: 'Endpoints for managing user accounts and profiles',
    priority: 1  // Controls display order
)]

Generated Documentation Features

The generated OpenAPI documentation includes:

  • Authentication Detection - Automatically identifies protected routes via middleware or attributes
  • Security Schemes - Bearer token authentication schema included
  • Request Schemas - All request bodies are stored as reusable components in components/schemas
  • Response Schemas - DTOs with computed fields are fully documented
  • URL Parameters - Path and query parameters with full validation rules
  • Validation Rules - Field types, formats, minimums, maximums, enums, etc.
  • Descriptions - Custom descriptions from attributes with markdown support
  • Pagination - Paginated responses include links and metadata schemas
  • Error Responses - Standard error response schemas
  • Smart Tagging - Organized by category with 'Auth' tag for protected endpoints
  • Test Coverage - Validates that routes have corresponding tests

Testing Integration

The documentation generator can validate your test coverage:

php artisan api:generate-docs --validate-tests --show-warnings

Output:

Test Coverage Analysis:

Total Routes: 15
Tested Routes: 12
Coverage: 80%

Routes Missing Tests:
  โ€ข GET /api/users/{user}/posts
    Add test: $this->getJson('/api/users/{user}/posts')
  โ€ข DELETE /api/posts/{post}
    Add test: $this->deleteJson('/api/posts/{post}')

The validator:

  • Scans your tests/Feature and tests/Unit directories
  • Checks if route URIs or names appear in test files
  • Provides actionable recommendations for missing tests
  • Calculates overall test coverage percentage

Example Generated Schema

{
  "openapi": "3.0.0",
  "info": {
    "title": "My API",
    "version": "v1"
  },
  "tags": [
    {
      "name": "Auth",
      "description": "Authentication and authorization endpoints"
    },
    {
      "name": "Users",
      "description": "User management endpoints"
    }
  ],
  "paths": {
    "/api/users": {
      "get": {
        "summary": "List all users",
        "description": "Retrieves a paginated list of all users in the system\n\n**Authentication Required:** Yes",
        "tags": ["Users", "Auth"],
        "security": [{"bearerAuth": []}],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {"type": "integer"},
            "example": 1
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "UserDTO": {
        "type": "object",
        "description": "DTO for User (includes all model attributes + computed fields)",
        "properties": {
          "id": {"type": "integer"},
          "name": {"type": "string"},
          "email": {"type": "string"},
          "posts_count": {
            "type": "integer",
            "description": "Computed field from postsCount"
          }
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Enter your bearer token in the format: Bearer {token}"
      }
    }
  }
}

Configuration

Key configuration options in config/api-responder.php:

return [
    // API routing detection
    'routing' => [
        'prefix' => env('API_PREFIX', 'api'), // Set to '' for no prefix
        'detect_json' => true,
    ],

    // Response structure keys
    'structure' => [
        'success_key' => 'success',
        'data_key' => 'data',
        'message_key' => 'message',
        'errors_key' => 'errors',
        'meta_key' => 'meta',
    ],

    // Exception messages (customizable)
    'exception_messages' => [
        'authentication' => 'Unauthenticated',
        'validation' => 'Validation failed',
        'not_found' => 'Resource not found',
        // ... more
    ],

    // Enable/disable features
    'cache' => ['enabled' => true],
    'sparse_fieldsets' => ['enabled' => true],
    'versioning' => ['enabled' => true],
    'batch' => ['enabled' => true],
    
    // Customize behavior
    'pagination' => ['default_per_page' => 15],
    'visibility' => ['resolve_user' => fn() => auth()->user()],
];

Customizing API Prefix

The package supports flexible API route detection:

// No prefix - handle all routes
'routing' => ['prefix' => ''],

// Custom prefix
'routing' => ['prefix' => 'v1'],

// Via environment variable
API_PREFIX=api/v2

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This package is open-sourced software licensed under the MIT license.

Credits

Support

For issues, questions, or contributions: