withRouting( api: __DIR__.'/../routes/api.php', // NOSONAR web: __DIR__.'/../routes/web.php', commands: __DIR__.'/../routes/console.php', health: '/up', then: function (): void { // Auto-discovery: ogni file in routes/api/ è caricato come gruppo sotto // prefisso `api` e stack `api`. Aggiungere un modello = creare un file lì, // senza toccare questo bootstrap. glob() ordina alfabeticamente → ordine // di registrazione deterministico. (Dopo aver aggiunto un file, se usi la // route cache rilancia `route:cache`, come per qualunque nuova rotta.) foreach (glob(base_path('routes/api/*.php')) as $routeFile) { Route::middleware('api')->prefix('api')->group($routeFile); } }, ) ->withMiddleware(function (Middleware $middleware): void { // per Sanctum $middleware->statefulApi(); // App API-only: nessuna rotta 'login' esiste. Senza questo, Laravel usa // il suo default redirectGuestsTo(route('login')) e un utente non // autenticato che richiede una pagina senza Accept: application/json // (es. browser diretto) genera RouteNotFoundException (500) invece di 401. $middleware->redirectGuestsTo(null); // Configurazione CORS $middleware->preventRequestForgery(except: ['api/*']); $middleware->alias([ 'admin' => IsAdmin::class, 'setup.complete' => EnsureSetupComplete::class, ]); // Tier riusabili nei file di routes/api/ — fonte di verità unica. // (nomi `tier.*` per non confliggere con l'alias `admin`.) $middleware->group('tier.app', ['auth:sanctum', 'verified', 'setup.complete']); $middleware->group('tier.admin', ['auth:sanctum', 'verified', 'admin', 'setup.complete']); $middleware->api(append: [ForceJsonResponse::class]); $middleware->trustProxies(at: '*'); }) ->withExceptions(function (Exceptions $exceptions): void { $exceptions->shouldRenderJsonWhen( fn (Request $request) => $request->is('api/*'), ); })->create();