Quando si parla di backend, chi sviluppa deve fare i conti con le route. Le route possono essere considerate la spina dorsale del backend, poiché ogni richiesta che il server riceve viene reindirizzata a un controller attraverso un elenco di routing che mappa le richieste ai controller o alle azioni.

Laravel ci nasconde molti dettagli di implementazione e include molto zucchero sintattico per aiutare sia chi è agli inizi con lo sviluppo che le persone più esperte a sviluppare le loro applicazioni web.

Vediamo nel dettaglio come gestire le route in Laravel.

Routing e Cross-Site Scripting in Laravel

Su un server esistono route pubbliche e private. Le route pubbliche possono essere fonte di preoccupazione a causa della possibilità di cross-site scripting (XSS), un tipo di attacco a injection che può lasciare voi e i vostri utenti vulnerabili a soggetti malintenzionati.

Il problema è che un utente può essere reindirizzato da una route che non richiede un token di sessione a uno che invece lo richiede, continuando ad avere accesso senza il token.

Il modo più semplice per risolvere questo problema è quello di applicare un nuovo heading HTTP, aggiungendo “referrer” al percorso per mitigare questo scenario:

'main' => [
  'path' => '/main',
  'referrer' => 'required,refresh-empty',
  'target' => ControllerDashboardController::class . '::mainAction'
]

Routing di Base in Laravel

In Laravel, i percorsi consentono agli utenti di indirizzare la richiesta appropriata al controller desiderato. La route Laravel più semplice accetta un Identificatore Uniforme di Attività (il percorso del routing) e una chiusura che può essere sia una funzione che una classe.

In Laravel, le route vengono create all’interno dei file web.php e api.php. Laravel è dotato di due route predefinite: una per il WEB e una per l’API.

Queste route si trovano nella cartella routes/, ma vengono caricate nel file Providers/RouteServiceProvider.php.

Una riga di comando che mostra lo stato predefinito del fornitore di servizi di route di Laravel.
Stato predefinito del provider di servizi di route di Laravel.

Invece di fare questo, possiamo caricare le route direttamente all’interno di RouteServiceProvider.php, saltando completamente la cartella routes/.

Una finestra a riga di comando che mostra il caricamento delle route Laravel direttamente nel provider.
Caricare le route di Laravel direttamente nel provider.

Reindirizzamenti

Quando definiamo una route, di solito vogliamo reindirizzare l’utente che vi accede e le ragioni di questa scelta variano molto. Può essere perché si tratta di una route deprecata e abbiamo cambiato il backend o il server, oppure perché vogliamo installare l’autenticazione a due fattori (2FA) e così via.

Laravel offre un modo semplice per farlo. Grazie alla semplicità del framework, possiamo usare il metodo redirect della facciata Route, che accetta la route di ingresso e quella verso cui essere reindirizzati.

Facoltativamente, possiamo indicare il codice di stato per il reindirizzamento come terzo parametro. Il metodo permanentRedirect avrà la stessa funzione del metodo redirect, con la differenza che restituirà sempre un codice di stato 301:

// Simple redirect
Route::redirect("/class", "/myClass");

// Redirect with custom status
Route::redirect("/home", "/office", 305);

// Route redirect with 301 status code
Route::permanentRedirect("/home", "office");

All’interno delle route di reindirizzamento è vietato usare le parole chiave “destination” e “status” come parametri perché sono riservate da Laravel.

// Illegal to use
Route::redirect("/home", "/office/{status}");

Viste

Le viste sono i file .blade.php che usiamo per rendere il frontend della nostra applicazione Laravel. Si serve del motore di template blade ed è il modo predefinito per costruire un’applicazione full-stack utilizzando solo Laravel.

Se vogliamo che la nostra route restituisca una vista, possiamo semplicemente usare il metodo view della facciata Route. Questo metodo accetta un parametro di route, un nome di vista e un array opzionale di valori da passare alla vista.

// When the user accesses my-domain.com/homepage
// the homepage.blade.php file will be rendered
Route::view("/homepage", "homepage");

Supponiamo che la nostra vista voglia dire “Ciao, {name}” passando un array opzionale con quel parametro. Possiamo farlo con il seguente codice (se il parametro mancante è richiesto dalla vista, la richiesta fallirà e verrà lanciato un errore):

Route::view('/homepage', 'homepage', ['name' => "Kinsta"]);

Elenco delle Routes

Con l’aumentare delle dimensioni della vostra applicazione, aumenterà anche il numero di richieste da instradare. E con una grande quantità di informazioni può nascere una grande confusione.

È qui che il sito artisan route:list command può aiutarci. Fornisce una panoramica di tutte le route definite nell’applicazione, dei relativi middleware e dei controller.

php artisan route:list

Mostra un elenco di tutte le route senza i middleware. A questo scopo, dobbiamo usare il flag -v:

php artisan route:list -v

In una situazione in cui si usa una progettazione orientata al dominio in cui i percorsi hanno nomi specifici nei loro percorsi, potete usare le capacità di filtraggio di questo comando in un modo simile:

php artisan route:list –path=api/account

Così verranno mostrati solo le route che iniziano con api/account.

D’altra parte, possiamo indicare a Laravel di escludere o includere le route definite da terzi con le opzioni –except-vendor o –only-vendor.

Parametri delle Routes

A volte potreste aver bisogno di catturare segmenti dell’URI con la route, come un ID utente o un token. Possiamo farlo definendo un parametro di route, che è sempre racchiuso tra parentesi graffe ({}) e deve essere composto solo da caratteri alfabetici.

Se le nostre route hanno delle dipendenze all’interno delle loro callback, il contenitore di servizi Laravel le inietterà automaticamente:

use IlluminateHttpRequest;
use Controllers/DashboardController;
Route::post('/dashboard/{id}, function (Request $request, string $id) {
  return 'User:' . $id;
}
Route::get('/dashboard/{id}, DashboardController.php);

Parametri Richiesti

I parametri obbligatori di Laravel sono parametri delle route che non possiamo saltare quando effettuiamo una chiamata. In caso contrario, verrà lanciato un errore:

Route::post("/gdpr/{userId}", GetGdprDataController.php");

Ora all’interno di GetGdprDataController.php avremo accesso diretto al parametro $userId.

public function __invoke(int $userId) {
  // Use the userId that we received…
}

Una route può contenere un numero qualsiasi di parametri. Questi vengono iniettati nei callback/controller della route in base all’ordine in cui sono elencati:

 // api.php
Route::post('/gdpr/{userId}/{userName}/{userAge}', GetGdprDataController.php);
// GetGdprDataController.php
public function __invoke(int $userId, string $userName, int $userAge) {
  // Use the parameters…
}

Parametri Opzionali

Se vogliamo fare qualcosa in una route quando è presente solo un parametro e nient’altro, senza influenzare l’intera applicazione, possiamo aggiungere un parametro opzionale. Questi parametri opzionali sono contrassegnati dal simbolo ?:

 Route::get('/user/{age?}', function (int $age = null) {
  if (!$age) Log::info("User doesn't have age set");
  else Log::info("User's age is " . $age);
}
Route::get('/user/{name?}', function (int $name = "John Doe") {
  Log::info("User's name is " . $name);
}

Carattere Jolly della Route

Laravel ci offre un modo per filtrare l’aspetto dei nostri parametri opzionali o obbligatori.

Supponiamo di volere una stringa di un ID utente. Possiamo convalidarla in questo modo a livello di route usando il metodo where.

Il metodo where accetta il nome del parametro e la regola regex che verrà applicata alla convalida. Per impostazione predefinita, accetta il primo parametro, ma se ne abbiamo molti, possiamo passare un array con il nome del parametro come chiave e la regola come valore e Laravel li analizzerà tutti per noi:

Route::get('/user/{age}', function (int $age) {
  //
}->where('age', '[0-9]+');
Route::get('/user/{age}', function (int $age) {
  //
}->where('[0-9]+');
Route::get('/user/{age}/{name}', function (int $age, string $name) {
  //
}->where(['age' => '[0-9]+', 'name' => '[a-z][A-z]+');

Possiamo fare un ulteriore passo avanti e applicare la convalida a tutti i percorsi della nostra applicazione utilizzando il metodo pattern sulla facciata Route:

 Route::pattern('id', '[0-9]+');

Questo metodo convaliderà ogni parametro di id con questa espressione regex. Una volta definita, verrà applicata automaticamente a tutte le route che usano quel nome di parametro.

Come possiamo vedere, Laravel usa il carattere / come separatore nel percorso. Se vogliamo usarlo nel percorso, dobbiamo consentire esplicitamente che faccia parte del nostro segnaposto utilizzando una regex where.

 Route::get('/find/{query}', function ($query) {
  //
})->where('query', , '.*');

L’unico inconveniente è che sarà supportato solo nell’ultimo segmento del percorso.

Routes con Nome

Come suggerisce il nome, possiamo dare un nome alle route, il che rende conveniente generare URL o reindirizzamenti per route specifiche.

Come Creare Route con Nome

Un modo semplice per creare una route con nome è fornito dal metodo name concatenato alla facciata Route. Il nome di ogni route deve essere unico:

 Route::get('/', function () {
})->name("homepage");

Gruppi di Routes

I gruppi di route vi permettono di condividere i loro attributi, come i middleware, su un gran numero di route senza doverli ridefinire su ogni singola route.

Middleware

Assegnare un middleware a tutti i percorsi che abbiamo ci permette di combinarli in un gruppo, prima di tutto utilizzando il metodo group. Una cosa da considerare è che i middleware vengono eseguiti nell’ordine in cui vengono applicati al gruppo:

 Route:middleware(['AuthMiddleware', 'SessionMiddleware'])->group(function () {
  Route::get('/', function() {} );
  Route::post('/upload-picture', function () {} );
});

Controller

Quando un gruppo usa lo stesso controller, possiamo usare il metodo controller per definire il controller comune a tutte le route del gruppo. Ora dobbiamo specificare il metodo che la route chiamerà.

 Route::controller(UserController::class)->group(function () {
  Route::get('/orders/{userId}', 'getOrders');
  Route::post('/order/{id}', 'postOrder');
});

Route del Sottodominio

Il nome di un sottodominio è un’informazione aggiuntiva che va all’inizio del nome di dominio di un sito web. Questo permette ai siti web di separare e organizzare i contenuti per funzioni specifiche, come negozi online, blog, presentazioni e così via, dal resto del sito.

Le nostre route si possono usare per gestire il routing dei sottodomini. Possiamo catturare il dominio e una porzione del sottodominio da usare nel nostro controller e nella nostra route. Con l’aiuto del metodo domain sulla facciata Route, possiamo raggruppare le nostre route sotto un unico dominio:

 Route::domain('{store}.enterprise.com')->group(function() {
  Route::get('order/{id}', function (Account $account, string $id) {
	// Your Code
  }
});

Prefissi e Prefissi dei Nomi

Ogni volta che abbiamo un gruppo di route, invece di modificarle una per una, possiamo usare le utilità extra che Laravel ci mette a disposizione, come per esempio prefix e name sulla facciata Route.

Il metodo prefix può essere utilizzato per prefissare ogni route del gruppo con un determinato URI, mentre il metodo name si può usare per prefissare il nome di ogni route con una determinata stringa.

Questo ci permette di creare nuovi elementi come le route amministrative senza dover modificare ogni singolo nome o prefisso per identificarle:

 Route::name('admin.")->group(function() {
  Route::prefix("admin")->group(function() {
	Route::get('/get')->name('get');
	Route::put('/put')->name(put');
	Route::post('/post')->name('post');
  });
});

Ora gli URI per queste route saranno admin/get, admin/put, admin/post e i nomi admin.get, admin.put e admin.post.

Caching delle Routes

Quando distribuisce l’applicazione sui server di produzione, un buon sviluppatore Laravel sfrutta la cache delle route di Laravel.

Cos’È la Cache delle Routes?

La cache delle route riduce il tempo necessario per registrare tutte le route dell’applicazione.

Eseguendo php artisan route:cache viene generata un’istanza di Illuminate/Routing/RouteCollection e, dopo essere stata codificata, l’output serializzato viene scritto in bootstrap/cache.routes.php.

Ora qualsiasi altra richiesta caricherà questo file di cache, se esiste. Pertanto, la nostra applicazione non deve più analizzare e convertire le voci del file dei percorsi in oggetti Illuminate/Routing/Route in Illuminate/Routing/RouteCollection.

Perché È Importante Usare la Cache delle Routes

Se non usate la funzione di caching delle route offerta da Laravel, la vostra applicazione rischia di funzionare più lentamente di quanto potrebbe, con il rischio di ridurre le vendite, la fidelizzazione degli utenti e la fiducia nel vostro marchio.

A seconda della scala del vostro progetto e del numero di route, l’esecuzione di un semplice comando di caching delle route può accelerare la vostra applicazione dal 130% al 500%: un guadagno enorme a fronte di uno sforzo quasi nullo.

Riepilogo

Il routing è la spina dorsale dello sviluppo backend. Il framework Laravel eccelle in questo senso, fornendo un modo verboso di definire e gestire i percorsi.

Lo sviluppo può essere accessibile a chiunque e contribuire a velocizzare un’applicazione solo in virtù del fatto che è stata realizzata in Laravel.

Quali altri trucchi e suggerimenti avete riscontrato riguardo alle rotte di Laravel? Fatecelo sapere nella sezione commenti!

Coman Cosmin

Cosmin Coman is a technology writer and developer with over 3 years of experience. Apart from writing for Kinsta, he has assisted in research at nuclear physics facilities and universities. Tech-savvy and integrated into the community, he always comes up with innovative solutions.