Controladores de recursos RESTful

Laravel incorpora un tipo especial de controlador, llamado controlador de recuso (recource controller), que facilita la construcción de controladores tipo RESTful. Para esto simplemente tendríamos que usar el comando de Artisan php artisan make:controller <nombre-controlador> --resource para crear el controlador y añadir la ruta al fichero de rutas routes/web.php usando Route::resource.

Por ejemplo, para crear un controlador para la gestión de imágenes almacenadas en la aplicación, en primer lugar ejecutaríamos el siguiente comando:

php artisan make:controller PhotoController --resource

Esto crearía el controlador PhotoController (incluyendo todos los métodos necesarios) en la carpeta app/Http/Controllers. Lo único que nos faltaría es registrar las rutas asociadas añadiendo al fichero routes/web.php la siguiente línea:

Route::resource('photo', 'PhotoController');

Esta línea de ruta crea por si sola múltiples rutas para gestionar todos los tipos de peticiones RESTful. Además, el controlador creado mediante Artisan estará preparado con todos los métodos necesarios para responder a todas las peticiones correspondientes. En la siguiente tabla se muestra un resumen de todas las rutas generadas, el tipo de petición a la que responden y la acción que realizan en el controlador:

Verbo

Ruta

Acción

Controlador / método

GET

/photo

index

PhotoController@index

GET

/photo/create

create

PhotoController@create

POST

/photo

store

PhotoController@store

GET

/photo/{resource}

show

PhotoController@show

GET

/photo/{resource}/edit

edit

PhotoController@edit

PUT/PATCH

/photo/{resource}

update

PhotoController@update

DELETE

/photo/{resource}

destroy

PhotoController@destroy

Restringir rutas en un controlador RESTful

En ocasiones nos interesará declarar solamente un subconjunto de las acciones que soporta REST, para esto, al declarar la ruta tipo resource tenemos que añadir un tercer parámetro con la opción only (para que solo se creen esas rutas) o except (para que se creen todas las rutas excepto las indicadas), por ejemplo:

Route::resource('photo', 'PhotoController',
                ['only' => ['index', 'show']]);

Route::resource('photo', 'PhotoController',
                ['except' => ['create', 'store', 'update', 'destroy']]);

Los métodos que no utilicemos los podremos borrar del código generado para el controlador.

Rutas adicionales en un controlador tipo RESTful

Si queremos definir rutas adicionales para un controlador de recursos simplemente las tenemos que añadir al fichero de rutas routes/web.php antes que las rutas del propio recurso, por ejemplo:

Route::get('photos/popular', 'PhotoController@getPopular');
Route::resource('photos', 'PhotoController');

Middleware

Para añadir middleware a un controlador tipo recurso tenemos dos opciones. La primera es definir un grupo que lo englobe, por ejemplo:

Route::group(['middleware' => 'auth'], function() {
    Route::resource('photo', 'PhotoController');
});

La otra opción es definir el middleware en el constructor del controlador de la forma:

class PhotoController extends Controller {
    public function __construct() {
        $this->middleware('auth');
        $this->middleware('log', ['only' => ['store', 'update', 'destroy']]);
    }
}

Definir una API mediante controladores RESTful

Si queremos definir una API, ya sea mediante controladores tipo RESTful o controladores normales, es recomendable que utilicemos el fichero de rutas routes/api.php en lugar de routes/web.php. En este fichero las rutas se definen exactamente de la misma forma que hemos estado viendo hasta ahora, usando la clase Route, los métodos get, post, put y delete, los controladores de recursos, los grupos de rutas, middleware, parámetros, etc. Además, al ejecutar el comando php artisan route:list estas rutas aparecerán en el mismo listado. Por lo que... ¿en qué se diferencian? Las diferencias entre estos ficheros de rutas son dos:

  • Los filtros o middleware que se utilizan: Mientras que en routes/web.php se aplican filtros para inicializar la sesión, las cookies, los bindings y la protección CSRF; en las rutas que se añadan a routes/api.php únicamente se aplican filtros para limitar el número de peticiones y para cargar los bindings (la inyección de dependencias). Esto lo podemos ver si editamos el fichero app/Http/Kernel.php, donde dentro de su array $middlewareGroups veremos dos grupos: web y api, con los filtros que se aplican en cada caso.

  • El prefijo de las rutas: A todas las rutas que especifiquemos en routes/api.php se les añadirá el prefijo api. Por lo que si añadimos la ruta users para devolver el listado de usuarios, para realizar la consulta tendremos que acceder a api/users. Esto lo podemos comprobar en el listado de rutas que muestra Artisan.

Estas diferencias aportan varias ventajas, por un lado tenemos separadas todas las rutas de la API tanto en un fichero distinto como por un prefijo, por lo que no se mezclarán los distintos tipos de rutas de nuestro sitio web. Además, las peticiones a las rutas de la API no tienen que cargar middleware innecesario, permitiéndonos también definir otros filtros propios de una API, como el de rate limit. Las peticiones a estas rutas no mantendrán sesión, por lo tanto se tendrán que autenticar bien mediante tokens o mediante seguridad HTTP básica (usando las cabeceras de la petición). Además, en las respuestas no tendremos que devolver una vista (con HTML), sino directamente el dato o la lista de datos solicitados en formato plano, en XML o en JSON.

En las siguientes secciones veremos cómo probar las rutas de una API, cómo protegerlas mediante autenticación HTTP básica y cómo devolver contenido correctamente formateado.

Last updated