Cuando se trata del backend, los desarrolladores acaban encontrándose con las rutas. Las rutas pueden considerarse la columna vertebral del backend, ya que cada solicitud que recibe el servidor se redirige a un controlador a través de una lista de rutas que asigna solicitudes a controladores o acciones.

Laravel nos oculta muchos detalles de implementación y viene con un montón de azúcar sintáctico para ayudar tanto a los desarrolladores nuevos como a los experimentados a desarrollar sus aplicaciones web.

Echemos un vistazo a cómo gestionar rutas en Laravel.

Rutas backend y Cross-Site Scripting en Laravel

En un servidor existen rutas públicas y privadas. Las rutas públicas pueden ser motivo de preocupación debido a la posibilidad de cross-site scripting (XSS), un tipo de ataque de inyección que puede dejarte a ti y a tus usuarios vulnerables ante actores maliciosos. El problema es que un usuario puede ser redirigido desde una ruta que no requiera un identificador de sesión a otra que sí lo requiera, y seguir teniendo acceso sin el identificador.

La forma más sencilla de resolver este problema es imponer una nueva cabecera HTTP, añadiendo «referrer» a la ruta para mitigar este escenario:

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

Enrutamiento básico de Laravel

En Laravel, las rutas permiten enrutar la solicitud adecuada al controlador deseado. La Ruta Laravel más básica acepta un Identificador Uniforme de Activos (la ruta de tu ruta) y un cierre que puede ser tanto una función como una clase.

En Laravel, las rutas se crean dentro de los archivos web.php y api.php. Laravel viene con dos rutas por defecto: una para la WEB y otra para la API.

Estas rutas residen en la carpeta routes/, pero se cargan en Providers/RouteServiceProvider.php.

Estado por defecto del proveedor de servicios de rutas de Laravel.
Estado por defecto del proveedor de servicios de rutas de Laravel.

En lugar de hacer esto, podemos cargar las rutas directamente dentro de RouteServiceProvider.php, saltándonos por completo la carpeta routes/.

Carga de rutas Laravel directamente en el proveedor.
Carga de rutas Laravel directamente en el proveedor.

Redirecciones

Cuando definimos una ruta, normalmente querremos redirigir al usuario que accede a ella, y las razones para ello varían mucho. Puede ser porque es una ruta obsoleta y hemos cambiado el backend o el servidor, o puede ser porque queremos instalar la autenticación de dos factores (2FA), etc.

Laravel tiene una forma sencilla de hacer esto. Gracias a la simplicidad del framework, podemos utilizar el método redirect en la fachada Route, que acepta la ruta de entrada y la ruta a la que redirigir.

Opcionalmente, podemos dar el código de estado de la redirección como tercer parámetro. El método permanentRedirect hará lo mismo que el método redirect, excepto que siempre devolverá un código de estado 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");

Dentro de las rutas de redirección tenemos prohibido utilizar las palabras clave «destino» y «estado» como parámetros, ya que están reservadas por Laravel.

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

Vistas

Las vistas son los archivos .blade.php que utilizamos para renderizar el frontend de nuestra aplicación Laravel. Utiliza el motor de plantillas blade, y es la forma por defecto de construir una aplicación full-stack utilizando únicamente Laravel.

Si queremos que nuestra ruta devuelva una vista, podemos utilizar simplemente el método view de la fachada Route. Acepta un parámetro de ruta, un nombre de vista y una matriz opcional de valores que se pasarán a la vista.

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

Supongamos que nuestra vista quiere decir «Hola, {name}» pasando una matriz opcional con ese parámetro. Podemos hacerlo con el siguiente código (si el parámetro que falta es necesario en la vista, la petición fallará y lanzará un error):

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

Lista de rutas

A medida que tu aplicación crece en tamaño, también lo hará el número de peticiones que necesitan ser enrutadas. Y con un gran volumen de información puede venir una gran confusión.

Aquí es donde artisan route:list command puede ayudarnos. Proporciona una visión general de todas las rutas que están definidas en la aplicación, sus middlewares y controladores.

php artisan route:list

Mostrará una lista de todas las rutas sin los middlewares. Para ello, debemos utilizar la bandera -v:

php artisan route:list -v

En una situación en la que puedas estar utilizando un diseño basado en dominios en el que tus rutas tengan nombres específicos en sus rutas, puedes hacer uso de las capacidades de filtrado de este comando de la siguiente manera:

php artisan route:list –path=api/account

Esto mostrará sólo las rutas que empiecen por api/cuenta. Por otra parte, podemos indicar a Laravel que excluya o incluya rutas definidas por terceros utilizando las opciones –except-vendor o –only-vendor.

Parámetros de ruta

A veces puede que necesites capturar segmentos de la URI con la ruta, como un ID de usuario o un token. Podemos hacerlo definiendo un parámetro de ruta, que siempre se encierra entre llaves ({}) y sólo debe constar de caracteres alfabéticos.

Si nuestras rutas tienen dependencias dentro de sus llamadas de retorno, el contenedor de servicios de Laravel las inyectará automáticamente:

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

Parámetros requeridos

Los parámetros obligatorios de Laravel son parámetros de las rutas que no podemos omitir al realizar una llamada. De lo contrario, se producirá un error:

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

Ahora dentro del GetGdprDataController. php tendremos acceso directo al parámetro $userId.

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

Una ruta puede tener cualquier número de parámetros. Se inyectan en las retrollamadas/controladores de la ruta en función del orden en que aparecen:

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

Parámetros opcionales

En una situación en la que queramos hacer algo en una ruta cuando sólo esté presente un parámetro y nada más, sin afectar a toda la aplicación, podemos añadir un parámetro opcional. Estos parámetros opcionales se denotan por el ? que se les añade:

 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);
}

Wildcard de ruta

Laravel nos proporciona una forma de filtrar cómo deben ser nuestros parámetros opcionales o requeridos.

Digamos que queremos una cadena de un ID de usuario. Podemos validarlo así a nivel de ruta utilizando el método where.

El método where acepta el nombre del parámetro y la regla regex que se aplicará en la validación. Por defecto, toma el primer parámetro, pero si tenemos muchos, podemos pasar un array con el nombre del parámetro como clave y la regla como valor, y Laravel los analizará todos por nosotros:

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]+');

Podemos llevar esto un paso más allá y aplicar la validación en todas las rutas de nuestra aplicación utilizando el método pattern en la fachada Route:

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

Esto validará cada parámetro id con esta expresión regex. Y una vez que la definamos, se aplicará automáticamente a todas las rutas que utilicen ese nombre de parámetro.

Como podemos ver, Laravel está utilizando el carácter / como separador en la ruta. Si queremos utilizarlo en la ruta, tenemos que permitir explícitamente que forme parte de nuestro marcador de posición utilizando una expresión regex where.

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

El único inconveniente es que sólo se admitirá en el último segmento de la ruta.

Rutas con nombre

Como su nombre indica, podemos asignar nombres a las rutas, lo que facilita la generación de URLs o redirecciones para rutas específicas.

Cómo crear rutas con nombre

Una forma sencilla de crear una ruta con nombre la proporciona el método name encadenado en la fachada Route. El nombre de cada ruta debe ser único:

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

Grupos de rutas

Los grupos de rutas te permiten compartir atributos de ruta, como los middlewares, entre un gran número de rutas sin necesidad de redefinirlos en todas y cada una de ellas.

Middleware

Asignar un middleware a todas las rutas que tenemos nos permite combinarlas en un grupo, primero utilizando el método group. Hay que tener en cuenta que los middlewares se ejecutan en el orden en que se aplican al grupo:

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

Controladores

Cuando un grupo utiliza el mismo controlador, podemos utilizar el método controller para definir el controlador común para todas las rutas de ese grupo. Ahora tenemos que especificar el método al que llamará la ruta.

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

Rutas de subdominio

Un nombre de subdominio es una información adicional que se añade al principio del nombre de dominio de un sitio web. Esto permite a los sitios web separar y organizar su contenido para funciones específicas, como tiendas online, blogs, presentaciones, etc., del resto del sitio web.

Nuestras rutas pueden utilizarse para gestionar el enrutamiento de subdominios. Podemos capturar el dominio y una parte del subdominio para utilizarlos en nuestro controlador y ruta. Con la ayuda del método domain de la fachada Route, podemos agrupar nuestras rutas bajo un único dominio:

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

Prefijos y prefijos de nombre

Siempre que tengamos un grupo de rutas, en lugar de modificarlas una a una, podemos hacer uso de las utilidades extra que proporciona Laravel, como prefix y name en la fachada Route.

El método prefix se puede utilizar para prefijar cada ruta del grupo con una URI dada, y el método name se puede utilizar para prefijar cada nombre de ruta con una cadena dada.

Esto nos permite crear cosas nuevas, como rutas de administrador, sin tener que modificar todos y cada uno de los nombres o prefijos para identificarlas:

 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');
  });
});

Ahora los URI de estas rutas serán admin/get, admin/put, admin/post, y los nombres admin.get, admin.put, y admin.post.

Almacenamiento en caché de rutas

Cuando despliegues la aplicación en servidores de producción, un buen desarrollador de Laravel aprovechará la caché de rutas de Laravel.

¿Qué es la caché de rutas?

La caché de rutas reduce el tiempo que se tarda en registrar todas las rutas de la aplicación.

Ejecutando php artisan route:cache se genera una instancia de Illuminate/Routing/RouteCollection, y tras ser codificada, la salida serializada se escribe en bootstrap/cache.routes.php.

Ahora cualquier otra petición cargará este archivo de caché si existe. Por lo tanto, nuestra aplicación ya no tiene que analizar y convertir las entradas del archivo de rutas en objetos Illuminate/Routing/Route en Illuminate/Routing/RouteCollection.

Por qué es importante utilizar el caché de rutas

Si no utilizas la función de caché de rutas que proporciona Laravel, tu aplicación corre el riesgo de funcionar más lentamente de lo que podría, lo que a su vez podría disminuir las ventas, la retención de usuarios y la confianza en tu marca.

Dependiendo de la escala de tu proyecto y de cuántas rutas haya, ejecutar un simple comando de almacenamiento en caché de rutas puede acelerar tu aplicación entre un 130% y un 500%, una ganancia enorme sin apenas esfuerzo.

Resumen

El enrutamiento es la columna vertebral del desarrollo backend. El framework Laravel destaca en esto al proporcionar una forma verbosa de definir y gestionar rutas.

El desarrollo puede ser realmente accesible para todos y ayudar a acelerar una aplicación sólo por el hecho de estar construida en Laravel.

¿Qué otros trucos y consejos has encontrado en relación con las rutas de Laravel? ¡Háznoslo saber en la sección de comentarios!

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.