Rutas, argumentos, vistas y métodos HTTP en Laravel

Video thumbnail

Como presentamos antes sobre la estructura de archivos y carpetas en Laravel, las rutas forma parte de estas rutas.

Las rutas en Laravel son el punto de entrada de cualquier aplicación.
En mi experiencia, entenderlas bien es el primer paso para dominar el framework.

Las rutas en Laravel son un esquema flexible que vincula una URI con un proceso funcional, que puede ser una función, un controlador o incluso un componente Livewire. En palabras simples: cuando un usuario escribe una dirección en el navegador, Laravel busca una coincidencia en los archivos de rutas y ejecuta la acción correspondiente.

El archivo principal que gestiona este proceso es routes/web.php. Aquí definimos las rutas que responden a las solicitudes del navegador, mientras que api.php, console.php o channels.php se usan para otros contextos como APIs o comandos de consola.

Cuando Laravel recibe una solicitud, pasa por su Front Controller (generalmente public/index.php), interpreta la URI y la asocia con la ruta correspondiente.

Las rutas, son un esquema flexible que tenemos para vincular una URI a un proceso funcional; y este proceso funcional, puede ser:

  1. Un callback, que es una función local definida en las mismas rutas.
  2. Un controlador, que es una clase aparte.
  3. Un componente, que es como un controlador, pero más flexible.

Si revisamos en la carpeta de routes; veremos que existen 4 archivos:

  1. api: Para definir rutas de nuestras Apis Rest.
  2. channels: Para la comunicación fullduplex con los canales.
  3. console: Para crear comandos con artisan.
  4. web: Las rutas para la aplicación web.

Tipos de rutas y métodos HTTP disponibles

El que nos interesa en este capítulo es el de web.php; el cual permite definir las rutas de nuestra aplicación web (las que nuestro cliente consume desde el navegador).

Las rutas en Laravel son un elemento central que nos permiten enlazar controladores, como poder desencadenar nuestros propios procesos; es decir, las rutas no necesitan de los controladores para poder presentar un contenido; y por ende, es el primer enfoque que vamos a presentar.

Si te fijas, tenemos una ruta ya definía:

Route::get('/', function () {
    return view('welcome');
});

Que como puedes suponer es la que nosotros vemos por pantalla nada más al arrancar la aplicación como la figura 2-1.

Fíjate, que se emplea una clase llamada Route, que se importa de:

use Illuminate\Support\Facades\Route;

Que es interna a Laravel y se conocen como Facades.

Los Facades no son más que clases que nos permiten acceder a servicios propios del framework mediante clases estáticas.

Finalmente, con esta clase, usamos un método llamado get(); para las rutas tenemos distintos métodos, tantos métodos como tipo de peticiones tenemos:

  • POST crear un recurso con el método post()
  • GET leer un recurso o colección con el método  get()
  • PUT actualizar un recurso con el método  put()
  • PATCH actualizar un recurso con el método patch()
  • DELETE eliminar un recurso con el método delete()

En este caso, empleamos una ruta de tipo get(), que conlleva a emplear a una petición de tipo GET.

El método get(), al igual que el resto de las funciones señaladas anteriormente, reciben dos parámetros:

Route::<FunctionResource>(URI, callback)
  1. URI de la aplicación.
  2. El callback viene siendo la función controladora, que en este caso es una función, pero puede ser la referencia a la función de un controlador o un componente.

Y donde "FunctionResource" es la method get(), post(), put(), patch() o delete().

En el ejemplo anterior, el “/“ indica que es el root de la aplicación, que es:

http://larafirststeps.test/

O localhost si empleas MacOS o Linux mediante Docker. 

En este caso, la parte funcional, viene siendo una función anónima; esta función, puede hacer cualquier cosa, devolver un JSON, un HTML, un documento, enviar un email y un largo etc.

En este ejemplo, devuelve una vista; para devolver vistas se emplea la función de ayuda (helper) llamada view(), la cual referencia las vistas que existen en la carpeta de:

resources/views/<Views and/or Folder>

Por defecto, solamente existe un único archivo; el llamado welcome.blade.php, y si, es el que estamos reverenciando en la ruta anterior con:

return view('welcome');

Fíjate, que no es necesario ni indicar la ruta, ni la extensión de blade o php.

Blade hace referencia al motor de plantillas que tiene Laravel que hablaremos sobre él un poco más adelante.

Si revisas la vista de welcome.blade.php:

Verás que todo el HTML de la misma:

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>
***

Así que, si creamos unas rutas más:

Route::get('/writeme', function () {
    return "Contact";
});

Route::get('/contact', function () {
    return "Enjoy my web";
});

Y vamos a cada una de estas páginas, respectivamente:

Ejemplo ruta 1
Ejemplo ruta 1

Y

Ejemplo ruta 2
Ejemplo ruta 2
Route::get('/custom', function () {
    $msj2 = "Msj from server *-*";
    $data = ['msj2' => $msj2, "age" => 15];
    return view('custom', $data);
 });

views/cursom.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p>{{ $msj2 }}</p>
    <p>{{ $age }}</p>
</body>
</html>
Ejemplo ruta 3
Ejemplo ruta 3

Rutas con nombre

Otra configuración que no puede faltar en tu aplicación, es el uso de rutas con nombre; como indica su nombre, le permite definir un nombre a una ruta.

***
Route::get('/contact', function () {
    return "Enjoy my web";
})->name('welcome');

Para eso se emplea una función llamada name() a la cual se le indica el nombre; para emplearla en la vista:

<a href="{{ name('welcome') }}">Welcome</a>

Esto es particularmente útil, ya que, puedes cambiar la URI de la ruta, agruparla o aplicarle cualquier otra configuración, pero, mientras tengas el nombre definido en la ruta y uses este nombre para referenciarla, Laravel va a actualizarla automáticamente.

Rutas dinámicas y parámetros

Las rutas también pueden recibir parámetros dinámicos:

Route::get('/user/{id}', function ($id) {
   return "Usuario con ID: $id";
});

Puedes hacerlos opcionales:

Route::get('/user/{name?}', function ($name = 'Invitado') {
   return "Hola, $name";
});

Y, por supuesto, pasar datos a una vista:

Route::get('/custom', function () {
   $msj2 = "Mensaje desde el servidor";
   $data = ['msj2' => $msj2, 'age' => 15];
   return view('custom', $data);
});

En este ejemplo, la vista custom.blade.php recibe variables y las muestra con Blade.

Me encanta este enfoque porque simplifica la comunicación entre el servidor y la interfaz.

Importancia de modularizar rutas en Laravel

Video thumbnail

Quiero comentarte algo que considero muy importante: modularizar tus rutas y controladores. Por controladores me refiero a las funciones o métodos que procesan las solicitudes. Para ilustrarlo, voy a mostrarte mi versión anterior de desarrollo en Laravel, para que veas la comparación.

En la versión anterior, tenía un montón de rutas GET como estas:

Route::get('{tutorial:url_clean}', [\App\Http\Controllers\Api\TutorialController::class, 'show']);
Route::get('/coupon/check/{coupon}', [\App\Http\Controllers\Api\CouponController::class, 'active']);
Route::get('update-progress-by-user', [App\Http\Controllers\Api\TutorialController::class, 'update_progress_by_user']);
Route::get('/get-detail/{tutorial:url_clean}', [App\Http\Controllers\Api\TutorialController::class, 'getAllDetail']);
Route::get('/by-slug/{tutorial:url_clean}', [App\Http\Controllers\Api\TutorialController::class, 'by_slug']);
Route::get('/class/free/by-slug/{tutorial:url_clean}', [App\Http\Controllers\Api\TutorialController::class, 'class_free_by_slug']);
Route::get('{id}/class/resume', [App\Http\Controllers\Api\TutorialController::class, 'get_class']);
Route::group(['middleware' => 'auth:sanctum'], function () {
   Route::post('inscribe/{tutorial:url_clean}', [App\Http\Controllers\Api\TutorialController::class, 'inscribe']);
   Route::get('user/my-courses', [App\Http\Controllers\Api\TutorialController::class, 'my_courses']);
});

Problema con las rutas desorganizadas

El motivo de tantas rutas es la anidación de cursos, secciones y clases, similar a cómo funciona Udemy:

  1. Curso principal (tutorial).
  2. Secciones del curso.
  3. Clases dentro de cada sección.

Además, dependiendo del usuario:

  • Si compró el curso, el tutorial tiene más información.
  • Si no lo compró, solo mostramos un detalle básico.

Esto llevaba a crear muchas rutas separadas para manejar diferentes vistas (detalle, full, simple) y diferentes filtros (ID o slug).

El problema es que estas rutas quedan poco comprensibles, con nombres largos y repetitivos, y se pierde modularidad.

Solución: agrupar y reutilizar controladores

Para simplificar, agrupamos las rutas y aprovechamos los mismos controladores:

Route::group(['prefix' => 'tutorial'], function () {
  Route::get('', [App\Http\Controllers\Api\TutorialController::class, 'getAll']); // listado general
  Route::get('simple/get-by-slug/{tutorial:url_clean}', [\App\Http\Controllers\Api\TutorialController::class, 'getSimple']);
  Route::get('simple/get-by-id/{tutorial}', [\App\Http\Controllers\Api\TutorialController::class, 'getSimple']);
  Route::get('full/get-by-slug/{tutorial:url_clean}', [\App\Http\Controllers\Api\TutorialController::class, 'getFull']);
  Route::get('full/get-by-id/{tutorial}', [\App\Http\Controllers\Api\TutorialController::class, 'getFull']);
});

Tip 1: reutilizar el mismo controlador para ID y slug

Si quieres traer un tutorial por ID o por slug, puedes usar el mismo controlador. Solo necesitas definir rutas adicionales:

Route::get('full/get-by-slug/{tutorial:url_clean}', [Controller::class, 'getFull']);
Route::get('full/get-by-id/{tutorial}', [Controller::class, 'getFull']);

Esto reduce la mitad de las rutas y hace el código más limpio y mantenible.

Tip 2: aprovechar parámetros y autenticación

En lugar de crear rutas adicionales, puedes aprovechar parámetros y autenticación para devolver más o menos información:

public function getFull(Tutorial $tutorial)
{
   $user = auth()->user() ?? auth('sanctum')->user();
   if ($user) {
       // Usuario autenticado: mostrar toda la información del tutorial
   } else {
       // Usuario no autenticado: mostrar solo información básica
   }
}

Para usuarios que no compraron el curso, se muestra solo la información básica.

Para usuarios que compraron el curso, se devuelve toda la información (full), incluyendo secciones y clases.

Se puede pasar un parámetro extra vía request para calcular precios adicionales, pero no se recomienda pasar información sensible directamente, ya que podría ser hackeada.

Beneficios de modularizar

Más fácil de mantener: no necesitas modificar múltiples rutas o controladores para agregar un nuevo parámetro.

Más legible: las rutas quedan agrupadas y con nombres claros.

Reutilización de controladores: puedes usar el mismo método para varias rutas y parámetros.

Seguridad: al usar auth o sanctum, los datos sensibles se manejan correctamente.

Errores comunes y cómo solucionarlos

Problema    Causa    Solución
Ruta no encontrada    URI mal escrita o ruta duplicada    Verifica con php artisan route:list
Error 419 o CSRF    Falta el token en formularios POST    Añade @csrf en los formularios
Cache de rutas desactualizada    Cambios sin limpiar cache    Ejecuta php artisan route:clear

Preguntas frecuentes (FAQs)

  • ¿Dónde se definen las rutas en Laravel?
    • En los archivos dentro de la carpeta routes/, principalmente en web.php.
  • ¿Cómo pasar variables a una vista desde una ruta?
    • Usa el helper view() y pasa un array asociativo con los datos.
  • ¿Qué diferencia hay entre rutas web y api?
    • Las rutas web cargan sesiones, cookies y vistas; las api son ligeras y sin estado.
  • ¿Cómo listar todas las rutas disponibles?
    • Con php artisan route:list.
  • ¿Cuál es la mejor forma de agrupar rutas?
    • Usar prefix(), middleware() o incluso Route::resource() para controladores REST.

Conclusión

Modularizar tus rutas y controladores es fundamental para mantener un proyecto ordenado, escalable y seguro. Esto evita el caos de rutas largas y confusas, y te permite aprovechar parámetros y autenticación para manejar diferentes escenarios con menos código.

Dominar su uso no solo te hace más eficiente, sino que te da control total sobre la estructura y rendimiento de tu aplicación.

La siguiente tarea, es conocer como emplear la poderosa línea de comandos de Laravel, Artisan.

Acepto recibir anuncios de interes sobre este Blog.

Daremos los primeros pasos con las rutas y las vistas, para empezar a ver pantallas a través del navegador; también cubriremos el uso de controladores con vistas; redirecciones, directivas y blade como motor de plantillas.

| 👤 Andrés Cruz

🇺🇸 In english