Configuration
Configuration Guide
Core Configuration (config/record.php)
return [
// Multi-tenant mode (optional)
'enable_tenant_id' => false,
'tenant_column' => 'tenant_id',
'tenant_header' => 'X-Tenant-ID',
'table_config_path' => 'records/tables',
// API route prefix
'api_prefix' => 'api/v1',
// permission
'permission_separator' => ':', // separator for permission ex: view:invoice
'restrict_to_own_records' => false, // limit queries to records created by the authenticated user
'own_records_permission_prefix' => 'viewOwn', // example: viewOwn_invoice
// Global limits
'per_page_max' => 10000,
'limit_max' => 10000,
'bulk_max' => 1000,
// Relationship nesting limit
'max_depth' => 10,
// Query caching (used by QueryCacheService)
'cache' => [
'enabled' => env('RECORD_API_CACHE_API', false),
'ttl' => 3600,
'prefix' => 'record_api',
'per_table' => [],
],
// Global RPC function configurations
'global_functions' => [],
// Table configurations
'tables' => [
// Your table configurations here
],
];Large Schemas (Many Tables)
For applications with many tables and global RPC functions, you can split configurations into multiple files and merge them in config/record.php. For example:
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use Mylekha\RecordApi\Types\RecordTableType;
$tables = [
// Core tables defined inline
];
$globalFunctions = [];
$tablesDirectory = __DIR__ . '/records/tables';
$globalFunctionsDirectory = __DIR__ . '/records/globalFunctions';
if (is_dir($tablesDirectory)) {
$directoryIterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($tablesDirectory)
);
foreach ($directoryIterator as $file) {
if (!$file->isFile() || $file->getExtension() !== 'php') {
continue;
}
$path = $file->getPathname();
$config = require $path;
if ($config instanceof RecordTableType) {
$name = pathinfo($path, PATHINFO_FILENAME);
$tables[$name] = $config;
} elseif (is_array($config)) {
$tables = array_merge($tables, $config);
}
}
}
if (is_dir($globalFunctionsDirectory)) {
$globalFunctionsDirectoryIterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($globalFunctionsDirectory)
);
foreach ($globalFunctionsDirectoryIterator as $file) {
if (!$file->isFile() || $file->getExtension() !== 'php') {
continue;
}
$path = $file->getPathname();
$config = require $path;
if (!is_array($config)) {
continue;
}
$group = pathinfo((string) $path, PATHINFO_FILENAME);
foreach ($config as $functionName => $functionConfig) {
if (!is_string($functionName) || $functionName === '') {
continue;
}
$normalizedFunctionName = ltrim($functionName, '/');
$prefixedFunctionName = str_contains($normalizedFunctionName, '/')
? $normalizedFunctionName
: $group . '/' . $normalizedFunctionName;
$globalFunctions[$prefixedFunctionName] = $functionConfig;
}
}
}
return [
'api_prefix' => 'api/v1',
'enable_tenant_id' => false,
'tenant_column' => 'tenant_id',
'tenant_header' => 'X-Tenant-ID',
'max_depth' => 10,
'cache' => [
'enabled' => env('RECORD_API_CACHE_API', false),
'ttl' => 3600,
'prefix' => 'record_api',
'per_table' => [],
],
'global_functions' => $globalFunctions,
'tables' => $tables,
];Each file under config/records/tables can return a single RecordTableType or an array of [table_name => RecordTableType]. Each file under config/records/globalFunctions must return an array. File name becomes group prefix for keys without / (example: auth.php + login => auth/login).
Authentication Setup
Record API does not ship its own authentication driver. Instead, it uses the Laravel auth guard you configure in config/record-api.php, which can point to any driver (JWT, Sanctum, Passport, etc.):
return [
'auth' => [
'guard' => env('RECORD_API_AUTH_GUARD', 'api'),
],
];Configure your desired guard in config/auth.php and set RECORD_API_AUTH_GUARD accordingly.
Option A: JWT Authentication
# Install JWT package
composer require php-open-source-saver/jwt-auth
php artisan vendor:publish --provider="PHPOpenSourceSaver\JWTAuth\Providers\LaravelServiceProvider"
php artisan jwt:secretConfigure your User model:
use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
return [];
}
}Option B: Laravel Sanctum
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrateMiddleware Configuration
Record API routes already include request.id. If you want request IDs on your own endpoints too, apply it to your routes:
Route::middleware(['api', 'auth:api', 'request.id'])->group(function () {
// Your API routes
});Step 7: Queue Configuration (Optional but Recommended)
For optimal performance with audit logging, configure queues:
# Install Redis (recommended)
composer require predis/predis
# Or use database queues
php artisan queue:table
php artisan migrateUpdate your .env:
QUEUE_CONNECTION=redis
# or
QUEUE_CONNECTION=databaseStart the queue worker:
php artisan queue:workStep 8: Permissions Setup (Optional)
If you install Spatie Laravel Permission, you can set it up like this:
# Publish the permission migration
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
# Run the migration
php artisan migrateCreate basic permissions for your tables:
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
// Create permissions for your tables
Permission::create(['name' => 'view_users']);
Permission::create(['name' => 'create_users']);
Permission::create(['name' => 'update_users']);
Permission::create(['name' => 'delete_users']);
// Create roles and assign permissions
$adminRole = Role::create(['name' => 'admin']);
$adminRole->givePermissionTo(['view_users', 'create_users', 'update_users', 'delete_users']);
$userRole = Role::create(['name' => 'user']);
$userRole->givePermissionTo(['view_users']);Add the trait to your User model:
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasRoles;
// Your model code
}Per-Table Custom Permission Names
Instead of relying on the auto-generated pmsName:action pattern, you can declare exact permission names per action directly on RecordTableType using the permissions property:
'items' => new RecordTableType(
table: 'items',
pmsName: 'item', // fallback for any action not in the permissions map
permissions: [
'read' => 'view_list_item',
'create' => 'insert_new_item',
'update' => 'update_existing_item',
'delete' => 'remove_item',
'restore' => 'restore_item',
],
),Partial overrides are supported — actions not listed fall back to the standard pmsName-based generation. Values can also be arrays for OR-logic: 'read' => ['view_item', 'admin_access'].
No breaking change:
permissions: null(the default) preserves identical behavior to previous versions.
Configuration
Publishing Configuration Files
# Publish main package configuration
php artisan vendor:publish --tag=record-api-config
# Publish all configurations (record, audit, record-api)
php artisan record-api:setupMain Configuration (config/record-api.php)
return [
'response' => [
'include_request_id' => env('RECORD_API_INCLUDE_REQUEST_ID', true),
],
'openapi' => [
'output' => env('RECORD_API_OPENAPI_OUTPUT', 'storage/openapi-schema.json'),
'info' => [
'title' => env('APP_NAME', 'Laravel API'),
'version' => '2.0.0',
'description' => 'Comprehensive API documentation with dynamic CRUD operations...',
],
'servers' => [
[
'url' => env('APP_URL', 'http://localhost'),
'description' => 'Development server',
],
],
],
];Record Configuration (config/record.php)
Controls database table operations and OpenAPI generation:
return [
'enable_tenant_id' => false,
'api_prefix' => 'api/v1',
'global_functions' => [
// Define custom RPC functions here
// 'functionName' => YourFunctionClass::class,
],
// Table-specific configurations...
];Advanced Configuration
Performance Optimization
1. Database Optimization
// config/record.php
return [
// Limit relationship nesting depth for better performance
'max_depth' => 2,
// Enable/disable query caching
'cache' => [
'enabled' => true,
'ttl' => 3600,
],
];2. Redis Configuration
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis3. Queue Optimization
# Use multiple queue workers
php artisan queue:work --queue=high,default --tries=3 --timeout=60
# Use Supervisor for production
sudo apt-get install supervisorSecurity Configuration
1. API Rate Limiting
The package routes use throttle:api-reads, throttle:api-writes, and throttle:api-functions. Define those limiters in your application (example shown in the installation steps).
2. CORS Configuration
Laravel ships CORS configuration out of the box. Configure it in your app via config/cors.php.
3. API Versioning
// config/record.php
return [
'api_prefix' => 'api/v1',
];Multi-tenancy Setup
// config/record.php
return [
'enable_tenant_id' => true,
'tenant_column' => 'tenant_id',
'tenant_header' => 'X-Tenant-ID',
];When enable_tenant_id=true, requests for tables configured with hasTenantId=true must include the tenant header (default: X-Tenant-ID).
Custom Middleware
// Register custom middleware
protected $middlewareGroups = [
'api' => [
\App\Http\Middleware\TenantMiddleware::class,
\Mylekha\RecordApi\Http\Middleware\RequestId::class,
\App\Http\Middleware\ApiVersioning::class,
],
];