Skip to content

Record Middleware Map ​

This guide explains how record.middleware_map resolves middleware stacks for CRUD and function endpoints.

Where to Configure ​

Configure in config/record.php:

php
'middleware_map' => [
    'default' => [
        '*' => [],
        'read' => [],
        'write' => ['auth:sanctum'],
        'function' => ['auth:sanctum'],
    ],
    'tables' => [
        // table-specific overrides
    ],
],

This map is used by record.route.middleware:{action}.

Not Applied to MCP or AI SDK Tools ​

record.route.middleware is attached to the CRUD and function routes only. The Data MCP routes (/{api_prefix}/mcp/...) use record.mcp.middleware instead, the stdio server (sp-laravel-api:mcp) runs no HTTP middleware, and the AI SDK record tools run inside whatever request or queued job prompts the agent. Middleware you rely on for tenancy (resolved_tenant_id), pgsql.tenant, subscriptions or rate limits must be added to record.mcp.middleware as well.

Resolution Order (Priority) ​

For each request, middleware is merged in this exact order:

  1. default['*']
  2. default[{group}]
  3. default[{action}]
  4. tables[{table}]['*']
  5. tables[{table}][{group}]
  6. tables[{table}][{action}]

Result is normalized, duplicates are removed, and invalid/self-recursive route middleware entries are skipped.

Action Groups ​

Group mapping used by runtime:

  • read: list, show
  • write: create, update, delete, restore, force_delete, upsert, bulk, bulk_create, bulk_update, bulk_delete, bulk_upsert
  • function: table_function, global_function

Example: Public Read, Auth Write, Subscribed Orders ​

php
'middleware_map' => [
    'default' => [
        '*' => [],
        'read' => [],
        'write' => ['auth:sanctum'],
        'function' => ['auth:sanctum'],
    ],
    'tables' => [
        'orders' => [
            'write' => ['auth:sanctum', 'subscribed'],
            'table_function' => ['auth:sanctum', 'subscribed'],
        ],
    ],
],

Function-Level Middleware Override ​

For table_function and global_function, RecordFunctionType::middleware can override the map:

  • If middleware is non-null, it replaces middleware_map entirely for that function.
  • If middleware is null, normal middleware_map resolution is used.
  • If middleware is [], no middleware is applied for that function.
  • Plain-array function configs do not support this override path.

Example:

php
'global_functions' => [
    'health/check' => new RecordFunctionType(
        httpMethod: [\Sopheak\Core\Enums\RecordFunctionMethodEnum::GET->value],
        class: \App\Api\Functions\HealthCheckFunction::class,
        functionName: 'handle',
        middleware: ['auth:sanctum', 'subscribed'],
    ),
],

Quick Troubleshooting ​

  • Middleware not applied: verify action key (write vs create vs table_function).
  • Table override not applied: verify route {table} matches tables key exactly.
  • Function override not applied: ensure function config resolves to RecordFunctionType (or class-based function), not plain array.