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:
'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:
default['*']default[{group}]default[{action}]tables[{table}]['*']tables[{table}][{group}]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,showwrite:create,update,delete,restore,force_delete,upsert,bulk,bulk_create,bulk_update,bulk_delete,bulk_upsertfunction:table_function,global_function
Example: Public Read, Auth Write, Subscribed Orders
'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
middlewareis non-null, it replacesmiddleware_mapentirely for that function. - If
middlewareisnull, normalmiddleware_mapresolution is used. - If
middlewareis[], no middleware is applied for that function. - Plain-array function configs do not support this override path.
Example:
'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 (
writevscreatevstable_function). - Table override not applied: verify route
{table}matchestableskey exactly. - Function override not applied: ensure function config resolves to
RecordFunctionType(or class-based function), not plain array.