withRouting( web: __DIR__.'/../routes/web.php', api: __DIR__.'/../routes/api.php', apiPrefix: 'api/v1', commands: __DIR__.'/../routes/console.php', channels: __DIR__.'/../routes/channels.php', health: '/up', ) ->withMiddleware(function (Middleware $middleware) { $middleware->statefulApi(); $middleware->alias([ 'role' => EnsureUserHasRole::class, 'tenant' => ResolveTenant::class, ]); // Run tenant resolution on every API request — public lookups // need it too so the bookkeeping is consistent. $middleware->prependToGroup('api', QueryTokenAuth::class); $middleware->prependToGroup('api', ResolveTenant::class); $middleware->redirectGuestsTo(function (Request $request) { return $request->is('api/*') ? null : null; }); }) ->withExceptions(function (Exceptions $exceptions) { // Report unhandled exceptions to Sentry. No-op when SENTRY_LARAVEL_DSN // isn't set (e.g., local/testing) — keeps the dev loop quiet. Integration::handles($exceptions); $exceptions->shouldRenderJsonWhen(function (Request $request) { return $request->is('api/*') || $request->expectsJson(); }); $exceptions->render(function (ValidationException $e, Request $request) { if ($request->is('api/*') || $request->expectsJson()) { \Illuminate\Support\Facades\Log::error('API Validation Failed: ' . json_encode($e->errors())); return ApiResponse::error( 'Validation failed', $e->errors(), Response::HTTP_UNPROCESSABLE_ENTITY, ); } }); $exceptions->render(function (AuthenticationException $e, Request $request) { if ($request->is('api/*') || $request->expectsJson()) { return ApiResponse::error('Unauthenticated', null, Response::HTTP_UNAUTHORIZED); } }); $exceptions->render(function (NotFoundHttpException $e, Request $request) { if ($request->is('api/*') || $request->expectsJson()) { return ApiResponse::error('Resource not found', null, Response::HTTP_NOT_FOUND); } }); $exceptions->render(function (HttpExceptionInterface $e, Request $request) { if ($request->is('api/*') || $request->expectsJson()) { return ApiResponse::error( $e->getMessage() ?: 'Request failed', null, $e->getStatusCode(), ); } }); })->create();