Vamos a añadir Swagger a nuestro proyecto API REST con Laravel, con Swagger y Swagger UI vamos a poder documentar y exponer de forma organizada los End points de nuestra API.
Swagger es un conjunto de herramientas de código abierto creadas en base a la documentación de OpenAPI que nos ayuda a documentar, crear, definir, y consumir nuestras APIs de una forma sencilla. Como veremos a lo largo de esta publicación Swagger funciona a través de anotaciones en los comentarios proporcionandonos a través de las mismas múltiples funcionalidades para documentar y probar nuestros End Points.
En esta publicación vamos a ver la instalación de Swagger en un proyecto API REST con Laravel, y la utilización de las anotaciones, todo esto lo realizaremos sobre un proyecto ya publicado en esta web.
Instalaremos Swagger en un proyecot que ya creado en Código Xules, y lo haremos cogiendo la parte de la API de Aplicación de microservicios con Laravel y RabbitMQ : 1. EL PROYECTO , para ver como funciona Swagger puedes seguir las explicaciones en tu propio proyecto, si quieres tener como base mi proyecto tendrás que seguir primero las publicaciones siguientes para crear la API de entreprises que será la que documentemos aquí:
- 2. Proyecto backend ADMIN-APP con Docker Compose : Laravel, Nginx y MySQL: creación del proyecto ADMIN-APP con Laravel donde desarrollamos una API CRUD para empresas (enterprises) y clientes (customers).
- 3.1. Desarrollamos el API REST de ADMIN-APP para empresas: desarrollo de la API CRUD de enterprises que será la que utilicemos como base para documentar esta aplicación.
Índice
En esta publicación vemos como instalar y configurar Swagger y ver como documentar los primeros end points:
- Instalación de Swagger en Laravel
- Documentamos con Swagger la API REST de enterprises
- Documentamos uno a uno los métodos de la API con Swagger
Software que utilizaremos
En este listado incluimos todo el software utilizado en todo el proyecto, no solo en esta publicación:
- Linux (Ubuntu 20.04 LTS): sistema operativo Linux con la versión de Ubuntu 20.04 LTS
- Docker (docker): Docker version 20.10.7, esta guía se ha generado utilizando esta versión de Docker.
- Docker compose (docker-compose): docker-compose version 1.25.0, , esta guía se ha generado utilizando esta versión
- Laravel 8: framewok PHP de desarrollo de aplicaciones web, en este caso utilizaremos la versión 8.
- Mysql 5.7: versión utilizada en la imagen de docker-compose para la base de datos.
- Nginx: servidor web de aplicaciones
- PHP 7.4: utilizamos PHP en una versión superior a 7.4 siguiendo las recomendaciones de Laravel, por eso la imagen que utilicemos será de esta versión.
- Artisan: programa de línea de comandos de Laravel que nos ayuda en la creación de elementos como modelos, controladores, …, y también, nos proporciona otras utilidades como gestión de las migraciones o el listado de las rutas
- Swagger: conjunto de herramientas de código abierto creadas en base a la documentación de OpenAPI que nos ayuda a documentar, crear, definir, y consumir nuestras APIs de una forma sencilla
1. Instalación de Swagger en Laravel
Para instalar Swagger en Laravel vamos a utilizar el módulo L5-Swagger en GitHub podéis consultar la información sobre la integración desarrollada por DarkaOnLine en Installation & Configuration.
En nuestro caso estamos trabajando con Laravel 8 la instalación que vamos a realizar aquí es válida para versiones de Laravel superiores a 6.X , y es muy sencilla.
Añadimos con Composer el módulo a nuestro proyecto (nuestro proyecto base esta con docker-compose por eso se ejecutan así los comandos, si no usas docker, pudes obviar la parte docker-compose exec admin-app-lpm):
$ docker-compose exec admin-app-lpm composer require "darkaonline/l5-swagger"
Si todo va bien podemos ver la instalación de paquetes que necesita el módulo:
Using version ^8.2 for darkaonline/l5-swagger ./composer.json has been updated Running composer update darkaonline/l5-swagger Loading composer repositories with package information Updating dependencies Lock file operations: 6 installs, 0 updates, 0 removals Locking darkaonline/l5-swagger (8.2.0) Locking doctrine/annotations (1.13.2) Locking psr/cache (1.0.1) Locking swagger-api/swagger-ui (v4.5.0) Locking symfony/yaml (v5.4.3) Locking zircote/swagger-php (4.2.6) Writing lock file Installing dependencies from lock file (including require-dev) Package operations: 6 installs, 0 updates, 0 removals Downloading symfony/yaml (v5.4.3) Downloading psr/cache (1.0.1) Downloading doctrine/annotations (1.13.2) Downloading zircote/swagger-php (4.2.6) Downloading swagger-api/swagger-ui (v4.5.0) Downloading darkaonline/l5-swagger (8.2.0) Installing symfony/yaml (v5.4.3): Extracting archive Installing psr/cache (1.0.1): Extracting archive Installing doctrine/annotations (1.13.2): Extracting archive Installing zircote/swagger-php (4.2.6): Extracting archive Installing swagger-api/swagger-ui (v4.5.0): Extracting archive Installing darkaonline/l5-swagger (8.2.0): Extracting archive Package swiftmailer/swiftmailer is abandoned, you should avoid using it. Use symfony/mailer instead. Generating optimized autoload files Illuminate\Foundation\ComposerScripts::postAutoloadDump @php artisan package:discover --ansi Discovered Package: darkaonline/l5-swagger Discovered Package: facade/ignition Discovered Package: fruitcake/laravel-cors Discovered Package: laravel/sail Discovered Package: laravel/sanctum Discovered Package: laravel/tinker Discovered Package: nesbot/carbon Discovered Package: nunomaduro/collision Discovered Package: vladimir-yuldashev/laravel-queue-rabbitmq Package manifest generated successfully. 80 packages you are using are looking for funding. Use the <code>composer fund</code> command to find out more! @php artisan vendor:publish --tag=laravel-assets --ansi --force No publishable resources for tag [laravel-assets]. Publishing complete.
Una vez instado podemos crear automáticamente la configuración en nuestro proyecto ejecutando:
$ docker-compose exec admin-app-lpm php artisan vendor:publish --provider "L5Swagger\L5SwaggerServiceProvider" Copied File [/vendor/darkaonline/l5-swagger/config/l5-swagger.php] To [/config/l5-swagger.php] Copied Directory [/vendor/darkaonline/l5-swagger/resources/views] To [/resources/views/vendor/l5-swagger] Publishing complete.
Cada vez que queramos actualizar la documentación de nuestro proyecto ejecutaremos la acción generate con el módulo l5-swagger de la siguiente forma:
$ docker-compose exec admin-app-lpm php artisan l5-swagger:generate
Si lo ejecutamos ahora directamente nos dará un error ya que aún no hemos definido ninguna etiqueta y no podrá generar la documentación, ejemplo:
Regenerating docs default ErrorException Required @OA\Info() not found at vendor/zircote/swagger-php/src/Loggers/DefaultLogger.php:31 27▕ } else { 28▕ $error_level = E_USER_WARNING; 29▕ } 30▕ ➜ 31▕ trigger_error($message, $error_level); 32▕ } 33▕ } 34▕ <code> +23 vendor frames </code> 24 artisan:37 Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
Entonces antes de ejecutar ese comando vamos a finalizar la configuración para empezar a documentar la aplicación, y después ejecutar la generación automática.
En nuestro proyecto Swagger se ha configurado automáticamente y puedes ver el fichero de configuración en config/l5-swagger.php , en este proyecto como no hemos definido temas de autentificación no vamos a entrar en detalles en esta parte, centrándonos en la documentación en el siguiente apartado.
Por úlitmos, si queremos fijar la ejecución automática de Swagger definimos en el fichero .env el siguiente parámetro:
L5_SWAGGER_GENERATE_ALWAYS=true
2. Documentamos con Swagger la API REST de enterprises
En nuestra API en la publicación 3.1. Desarrollamos el API REST de ADMIN-APP para empresas hemos desarrollado el API REST de enterprises, la documentación de Swagger la haremos en el controlador CmEnterpriseController veamos como.
2.1. Definición del controlador para Swagger
En nuestra clase CmEnterpriseController vamos a utilizar los comentarios para documentar la aplicación empezaremos utilizando la anotación @OA\Info para definir la información del controlador, empezaremos definiendo la versión, el título y la descripción como se puede ver a continuación:
/** * @OA\Info( * version="1.0.0", * title="L5 OpenApi documentación de Enterprises", * description="L5 Swagger OpenApi description para enterprises.", * ) */ class CmEnterpriseController extends Controller
Otras anotaciones que podemos añadir por ejemplo son:
- @OA\Contact: añadimos datos de contacto
- @OA\License: añadimos información sobre la licencia.
Vamos a añadir estás anotaciones y ver también como podemos añadir un logo (inicialmente incluimos el default):
/** * @OA\Info( * version="1.0.0", * title="L5 OpenApi", * description="L5 Swagger OpenApi description", * x={ * "logo": { * "url": "https://via.placeholder.com/190x90.png?text=L5-Swagger" * } * }, * @OA\Contact( * email="julio.yanez@codigoxules.org" * ), * @OA\License( * name="Apache 2.0", * url="https://www.apache.org/licenses/LICENSE-2.0.html" * ) * ) */ class CmEnterpriseController extends Controller
¿Qué pasa si ahora ejecutamos la generación de documentación?
$ docker-compose exec admin-app-lpm php artisan l5-swagger:generate
Pues que nos va a dar un error porque aún no hemos documentado ningún método y nos dirá que no encuentra ningún @OA\PathItem() que es necesario para generar la documentación, lo que ya tenemos es accesible la visualización web, en nuestro caso en http://localhost:28021/api/documentation, se ve así.
La información de la API en formato JSON se puede consultar en http://localhost:28021/docs/api-docs.json, como hemos dicho con la correspondencia hacia el estándar Open API 3.0:

Entonces vamos al siguiente punto a documentar los métodos.
3. Documentamos uno a uno los métodos de la API con Swagger
Vamos a ir repasando los métodos desarrollados en CmEnterpriseController y añadiéndoles la documentación. Los métodos implementados y que se corresponden a las operaciones CRUD son:
- index(): listado de todas las empresas.
- store(Request $request): creación de una nueva empresa.
- show($id): consulta de datos de una empresa.
- update(Request $request, $id): actualización de los datos de una empresa.
- destroy($id): eliminación de una empresa.
3.1. Listado de empresas: index()
Este método de la API va asociado a un GET que nos devuelve todas las empresas registradas, veamos la implementación del método, y a continuación vamos viendo cómo documentarlo:
public function index() { $enterprises = CmEnterprise::all(); $message = 'Empresas obtenidos correctamente'; $response = [ 'success' => true, 'data' => CmEnterpriseResource::collection($enterprises), 'message' => $message, ]; return response()->json($response, 200); }
Si inspeccionamos con route:list nuestro acceso a la API de listado de empresas (enterprises) vemos que se corresponde con:
- Domain:
- Method: GET|HEAD
- URI: api/enterprises
- Name: enterprises.index
- Action: App\Http\Controllers\API\CmEnterpriseController@index
- Middleware: api
Entonces vamos a ir llevando esa información con anotaciones para que desde la web generada con Swagger podamos ver la información y probar el End Point:
/** * Display a listing of the resource. * Mostramos el listado de los regitros solicitados. * @return \Illuminate\Http\Response * * @OA\Get( * path="/api/enterprises", * tags={"enterprises"}, * summary="Mostrar el listado de empresas", * @OA\Response( * response=200, * description="Mostrar todas las empresas." * ), * @OA\Response( * response="default", * description="Ha ocurrido un error." * ) * ) */ public function index()
En negrita os marco lo que se corresponde con la documentación para Swagger, como es un método GET utilizamos la anotación @OA\Get y le vamos añadiendo información del End Point y de las respuestas. También dejamos los comentarios que teníamos anteriormente para que veais como interactúa con ellos Swagger, es sencillo:
- path=»/api/enterprises»: definimos el path la URL de nuestro End Point
- tags={«enterprises»}: usamos el tag enterprises para agrupar en él todos los End Point de enterprises.
- summary=»Mostrar el listado de empresas»: descripción del End Point.
- @OA\Response: con esta anotación definimos como son cada un de las respuestas del End point desde el Ok con 200 a las de errores.
Cómo hemos marcado la actualización en automático de Swagger si vamos ahora directamente a la web ya podemos consultar el End point y ver el resultado, veámoslo paso a paso:
Paso 1: ahora ya nos aparece el métedo GET para /api/empresas dentro de enterprises
Paso 2: si desplegamos el endpoint vemos la información añadida y la opción Try it out para probar el endpoint.
Paso 3: al pulsar Try it out se genera automáticamente la opción de ejecutar la llamada a la API:
Paso 4: como nuestra consulta ha tenido éxito se muestra el código de respuesta 200 y la respuesta, además podemos ver la llamada a realizar con curl y la URL de la llamada (Request URL):
3.2. Consulta de una empresa: show($id)
Este método se genera con un método GET en la llamada con el id de la empresa tal que así: api/enterprises/1. Veamos el método desarrollado que sería el siguiente y nos devuelve los datos de la empresa consultada:
public function show($id) { $enterprise = CmEnterprise::find($id); if (is_null($enterprise)) { return response()->json( $response = [ 'success' => false, 'message' => 'No se ha encontrado la empresa.' ], 404); } $message = 'Empresa encontrada.'; $response = [ 'success' => true, 'data' => new CmEnterpriseResource($enterprise), 'message' => $message, ]; return response()->json($response, 200); }
Ahora lo documentamos utilizando la anotación
/** * Display the specified resource. * Muestra el registro solicitado * @param int $id * @return \Illuminate\Http\Response * @OA\Get( * path="/api/enterprises/{enterprise}", * tags={"enterprises"}, * summary="Mostrar info de una empresa", * @OA\Parameter( * description="Parámetro necesario para la consulta de datos de una empresa", * in="path", * name="enterprise", * required=true, * @OA\Schema(type="string"), * @OA\Examples(example="int", value="1", summary="Introduce un número de id de empresa.") * ), * @OA\Response( * response=200, * description="Mostrar info de una empresa." * ), * @OA\Response( * response=404, * description="No se ha encontrado la empresa." * ), * @OA\Response( * response="default", * description="Ha ocurrido un error." * ) * ) */ public function show($id)
Las anotaciones utilizadas y explicadas anteriormente ya no las desarrollamos porque se entienden por si mismas, en este caso definimos en la documentación que es obligatorio el paso del parámetro del id de empresa con la anotación @OA\Parameter :
- description: descripción del parámetro necesario
- required=true: indicamos que es obligatorio
- @OA\Schema(type=»string»),
- @OA\Examples(example=»int», value=»1″, summary=»Introduce un número de id de empresa.»): indicamos como sería un ejemplo para consultar la empresa con id = 1 que veremos como lo utilizar en la presentación web para lanzar la llamada al endpoint.
Cómo hicimos antes pulsamos Try it out para generar la llamada al End point con la diferencia que ahora podemos introducir los datos de la empresa que queremos consultar, como podemos ver en las siguientes imágenes:
Hasta aquí esta primera parte continuaremos con los métodos que faltan en una próxima publicación.