Creando un api

Creando una API

Términos importantes que hay que conocer

  • API
  • REST
  • VERBOS HTTP
  • RECURSOS
  • CÓDIGOS DE ESTADO


API

Una Interfez de programación de aplicaciones Son programas que permiten que otros programas se conecten con él para obtener recursos.

Para ello establecen una interfaz para que puedan conectarse a él.

Por un lado una aplicación solicita datos (request) , y la API se los devuelve (response) .

Application Programming Interface

API Programa que recibe solicitudes y envía respuesta a otros programas

REST

REpresentational State Transfer ( Transferencia de Estado representacional)

Estos principios indican cómo deben representarse los datos que se desean transferir , proporcionando una guía para el desarrollo de sistemas web eficientes y bien estructurados.

PRINCIPIOS QUE DEFINEN LA ARQUITECTURA DE REST


REST se basa en una serie de principios y restricciones que definen su arquitectura. A continuación, se resumen las seis guías o restricciones principales de REST:

Arquitectura Cliente-Servidor:

  • La arquitectura cliente-servidor separa la interfaz de usuario y la lógica del usuario (cliente) de la lógica del servidor.
  • Mejora la portabilidad del cliente y la escalabilidad del servidor, ya que cada parte puede evolucionar independientemente.
  • O sea que el API y el CLIENTE son dos entes independientes

Sin Estado (Stateless):

  • Cada solicitud del cliente al servidor debe contener toda la información necesaria para entender y procesar la solicitud.
  • El servidor no debe almacenar el estado del cliente entre solicitudes; cada solicitud desde un cliente se trata de forma independiente. (Ni cookies ni sesiones)
  • El estado de la sesión del usuario se mantiene en el cliente (usando tokens)

Cacheable (Almacenamiento en Caché):

  • Las respuestas del servidor deben indicar si se pueden almacenar en caché o no.
  • La caché puede mejorar la eficiencia y la escalabilidad al reducir la necesidad de recuperar la misma información una y otra vez.

Interfaz Uniforme:

  • Define una interfaz uniforme entre los componentes, lo que facilita la independencia y la evolución de cada componente.

  • La interfaz uniforme se compone de cuatro restricciones:

    • Identificación de Recursos: Cada recurso (información o servicio) se identifica mediante un URI (Uniform Resource Identifier).
    • Manipulación de Recursos a través de Representaciones: Los recursos pueden ser representados y manipulados en diferentes formatos, como JSON o XML.
    • Mensajes Autodescriptivos: Cada mensaje incluye suficiente información para describir cómo procesar la solicitud.
    • HATEOAS (Hypertext As The Engine Of Application State): La aplicación es conducida por hipermedios proporcionados dinámicamente a través de aplicaciones de navegadores, es decir

    el servidor debe de facilitar información que nos diga cómo navegar por la API, no solo facilitar datso

Sistema de Capas (Layered System):

  • La arquitectura se puede organizar en capas jerárquicas.
  • Cada capa realiza una funcionalidad específica y solo interactúa directamente con las capas adyacentes.

Codigo Bajo Demanda (Code on Demand) [opcional]:

  • Los clientes pueden descargar y ejecutar código (como applets o scripts) desde el servidor.
  • Esta restricción es opcional y no se utiliza comúnmente en aplicaciones RESTful.

Estas restricciones definen los principios clave de REST y proporcionan una guía para desarrollar sistemas web eficientes, escalables y bien estructurados.

Verbos HTTP

Si la API funciona con el protocolo HTTP, entonces establos hablando de una API RestFull HTTP sabemos que es un protocolo para transferir texto a través de internet

Resource

Representación

1 - 01_Introducción y 20_rutas

Creando el proyecto

Vamos a instalar e un

mkdir books
cd books
1
2
3
4
5
laravel new api --git
cd api
git init
git add *
git commit -m inicial

Vamos documentando el Readme.md

Creando los modelos, controladores y factorys

Para hacerlo de forma más rápida usamos blueprint

  1. Instalamos el paquete
 composer require laravel-shift/blueprint --dev
  1. Creamos el fichero de especificación de construcción
php_ artisan blueprint:new
  1. Especificamos en el fichero los modelos y los controladores
models:
  Profesor:
    nombre: string
    email: string
    proyecto_id: id
    relationships:
      hasMany: Proyecto
  Proyecto:
    titulo: string
    web: string
    horas: integer
    user_id: id
controllers:
  ProyectosController:
    resource: api
  ProfesoresController:
    resource: api.profesor
  UserController:
    resource: api 
  1. Modificamos previa publicación opciones de blueprint
  2. Primero publicamos
php_ artisan vendor:publish

2. Ahora modificamos el fichero generado en config/blueprint.yaml

//// . . . 
'use_constraints' => true,
////. . .
'use_guarded' => true,
///. . .
4. Ejecutamos el fichero

Rutas

Como la aplicación va a ser un API, vamos al fichero de rutas routes/api.php

Entre web.php y api.php hay como diferencias los middeleware que se utilizan. Esto se puede ver en


En el caso de api.php, casi el único middleware que utiliza es el ThrottleRequests, es decir, poder crear un límite de peticiones, no necesitamos sesiones, cookies ni compartir errores entre ficheros. Vemos si hacemos un route:list que las rutas que aparecen son las de web.php y también las de api.php que no habíamos visto Las de api tiene prefijo, es por que se establece en el routeservicesproviders.php

Ahora vamos a crar un modelo, y queremos crear también la migración y el factory y también un controlador con todos los métodos de gestión rest que ya hemos visto

1
php artisan make:model Book -mf --api
Ahora debemos de agregar rutas

imagen api

De todas ellas, como solo estamos creando un api, que es para consultar, no realizaremos la acción de editar para modificar, ni de crear por lo que las rutas nos quedarían

imagen api

Creamos estas rutas en el fichero routes/api.php
1
Route::apiResource('books', \App\Http\Controllers\BookController::class);
Podemos ejectura route:list para ver las 5 rutas que hemos creado

2 - Controlador

Ejecutar la migración

Debemos de crear la base de datos y poderla cargar

métodos de get

Para ello escribimos el código de index y show con las respectivas rutas

1
2
http://localhost:8000/api/books => obtener todos los libros
http://localhost:8000/api/books/1 => obtener el libro de id 1

Como lo que nos retorna es un Json, podemos instalar algún plugin para verlo de forma mas legible en el navegador, por ejemplo jsonview

metodos PATCH DELETE y POST

Ahora queremos probar estas otras rutas Para ello debemos de tener una herramienta que nos permita realizar llamadas de este tipo, con el navegador no podemos y estamos haciendo un api, no la parte de uso, sino de servicio Podemos instalar postman

1
2
3
sudo apt install snapd
sudo apt update
sudo snap install postman
*Podemos probar una solicitud por post y hacer que el método store me retorne un texto, lo mismo con patch y con delete y ver qué es

post

Vemos que con el post, en la parte del body del mensaje hay que aportar algún valor Para ello vamos al body y usamo el form-data para pasar valores

Pasar parámetros para el post

Escribmos el código del método store añadiendo un nuevo libro

Podemos ver qué ocurre si ponemos otro parámetro o no pasamos ningún libro

Para poder ver los errores debemos habilitar los hedear para en formato json aceptar los errores

Añadir la opción de ver los errores en el navegador

Podemos establecer en el servidor el control del error indicando lo que queramos que se muestre si no aparece el error

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
    public function store(Request $request)
    {
        $request->validate([
            'titulo'=>['required']
        ]);

        $book = new Book();
        $book->titulo=$request->input('titulo');
        $book->save();
        return $book;
        //
    }

PATH

La actualización es muy similar al storage, con la diferencia que solo queremos actualizar, no agregar En el postman, para pasar los nuevos datos usamos

modo de pasar datos al método patch

1
2
3
4
5
6
7
8
public function update(Request $request, Book $book){
        $request->validate([
                    'titulo'=>['required']
        ]);
        $book->titulo=$request->input('titulo');
        $book->update();
        return $book;
    }

DELETE

En este caso el método delete es muy sencillo. Podemos retornar un mensaje

1
2
3
4
5
public function destroy(Book $book)
{
$book->delete();
return "Se ha borrado ".$book->titulo;
}

3 - 3.La Vista unitarios

Tipos de test en laravel

Realizar test, es muy importante. Muchas veces pensamos que como no los necesitamos para que la apliación funcione lo dejamos para el final, o simplemente no lo hacemos (para ejemplo yo mismo 🥶 )

Laravel ya aporta una estructura de test, que podemos ver en la carpeta correspondiente. En ella vemos que tenemos dos tipos de test:

  • Feature

Test de características dónde se testean diferentes componentes interactuando entre ellos

  • Unit

Que testean métodos concretos del código

*El funcionamiento de los métodos creados es el muy parecido. Para esta api, vamos a realizar los test usando los FeatureText

Ejecutando los test en laravel

En el terminal escribimos

1
    php artisan test
Vamos a crear métodos para validar cada uno de los 5 métodos que tenemos en el controlador

Un test es un método que nos va a permitir validar otro método En el método del test, básicamente vamos a hacer 3 acciones *Invocar al método que queremos testear pasándole los valores que consideremos *Comprobar que lo que devuelve ese método que validamos es lo que esperamos que devuelva *Informar de ello

Los test no son infalibles, es decir, nosotros validamos lo que consideramos, por ejemplo si valido un método de fecha, si le paso una fecha incorrecta, espero que me lo diga, y si es correcta igual, eso me permitiría validar el método. Veamos cómo se realizan estas acciones **1.- Creamos una clase para el test del api. ** El método de test, se espera que termine con la palabra Test. Creamos una clase llamada BookApiTest para nuestro ejemplo
1
    php artisan make:test BookApiTest
Empezamos validando el método index para ello vamos a crear un método Importante que el método empiece por la palabra test
1
2
3
public function test_can_get_all_books(): void{

    }

Pero claro, necesitamos tener la base de datos poblada y comprobar que cuando consultamos obtenemos todos los registros Pero no queremos tocar la base de datos original, si no que vamos a craar una base de datos para los test, para lo cual vamos a usar la clase (traid) RefreshDatabase que nos ofrece Laravel Creamos una nueva base de datos (también podríamos usar sqlite en memoria) Para configurar la base de datos de test, primero la creamos en nuestro gestor

creamos la base de datos api_test

Ahora lo configuramos en el fichero phpunit.xml
1
2
3
4
5
6
<php>
<env name="APP_ENV" value="testing"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_DRIVER" value="array"/>
<!-- <env name="DB_CONNECTION" value="sqlite"/> -->
<env name="DB_DATABASE" value="api_test"/>
Para poblar la base de datos de pruebas, vamos a usar el factory que creamos cuando construimos el modelo

Una vez creado, lo invocamos desde el método credado Vamos simplemente a crear un libro y visualizarlo

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
//En el factory
public function definition(): array{
    return [
            'titulo'=>fake()->sentence(),
            ];
}

//En el test
public function test_can_get_all_books(): void{
        $book = Book::factory()->create();
        dd($book);
    }
Por ejemplo vamos a creaer 4 libros y verificamos que haya 4 libros
1
2
3
4
5
6
public function test_can_get_all_books(): void
{
    $book = Book::factory()->count(4)->create();
    dd($book->count());

}
Ahora vamos a ver lo que retorno si hacemos una solicitud get
1
2
3
4
5
public function test_can_get_all_books(): void
{
    $book = Book::factory()->count(4)->create();
    $this->get("/api/books")->dump();
}
Ahora que vemos esto, se trataría de verficar los libros que nos devuelve son los que hemos creado Para ello vamos a hacer uns aserción y verficar que esto funciona. para ello vamos a recoger la respuesta y vamos a comparar por ejemplo los títulos de los dos primeros libros recibidos con los títulos de los dos primeros libros creados.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public function test_can_get_all_books(): void
{
    $book = Book::factory()->count(4)->create();
    $response = $this->getJson(route("books.index"));
    $response->assertJsonFragment([
        'titulo'=>$book[0]->titulo
    ])
    ->assertJsonFragment([
                'titulo'=>$book[1]->titulo
    ]);

   }
 
Ejecutamos el test y vemos que funciona Probar por ejemplo a modificar el método index y ver que no funciona, por ejemplo si solo retornamos un libre en lugar de todos , o no devolvemos nada … **Verificar el método show
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
/**
* @test
*/
public function can_get_one_book():void{
    $book=Book::factory()->create();
    $response = $this->getJson(route("books.index"));
    $response->assertJsonFragment([
            'titulo'=>$book->titulo
    ]);
}
* Observa que si ponemos la directiva **@test** ya no hay que hacer que el nombre del método empiece por la palabra **test**
  
Verificar el método store
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
/**
* @test
*/
public function can_crate_book():void{

        $this->postJson(route('books.store'),[
            'titulo'=>"Mi libro de pruebas"
        ])->assertJsonFragment([
            'titulo'=>"Mi libro de pruebas"
        ]);
        $this->assertDatabaseHas('books',
            ['titulo'=>"Mi libro de pruebas"]
        );


}
En este caso hacemos dos aserciones, podemos ver cómo tanto con solo una, como con dos, funciona correctamente Vamos a ver cómo podemos también validar que si no le pasamos nada, nuestra aplicación esparemos que nos de un error. Por ejemplo si quitáramos la validación en el controlador,
1
2
3
4
public function can_crate_book():void{
    $this->postJson(route('books.store'),[])
    ->assertJsonValidationErrors('titulo');
/....
Actualizar un libro
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
/**
* @test
*/
public function can_update_book():void{
$book=Book::factory()->create();
$this->patch(route("books.update",$book),[
            'titulo'=>"Libro editado"
            ])->assertJsonFragment([
                'titulo'=>'Libro editado'
            ]);
            //Verificamos también en la base de datos
        $this->assertDatabaseHas('books',[
                'titulo'=>"Libro editado"
            ]);

        }
*Podemos (debemos) de verificar también la validación
1
2
3
//Validamos también la validación
$this->patch(route("books.update",$book),[])
->assertJsonValidationErrors('titulo');
Borrar un libro *En este caso vamos a eliminar un libro y verificar que no existe
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
/**
* @test
*/
public function can_delete_book(): void
{

        $book = Book::factory()->create();

        //Validamos también la validación
        $respuesta = $this->deleteJson(route("books.destroy", $book), [])
            ->assertContent("Se ha borrado ".$book->titulo);
//            ->assertNoContent();
}

4 - swagger

Referencias

Fuentes de Información


Swagger en Laravel 11

Introducción

Swagger (OpenAPI) es una herramienta que permite documentar APIs de manera estructurada y visual, facilitando su uso por parte de desarrolladores y otros sistemas.

En Laravel, la biblioteca L5 Swagger ayuda a integrar esta documentación automáticamente a partir de anotaciones en el código.

Este documento explica cómo configurar Swagger en Laravel 11 y cómo documentar los endpoints de una API.

Instalación de Swagger en Laravel 12

Instalamos con composer la librería darkaonline/l5-swagger

1
  composer require darkaonline/l5-swagger

Publicamos la configuración para ponerla disponible en el direcotiro del proyecto.

1
php artisan vendor:publish --provider="L5Swagger\\L5SwaggerServiceProvider"

Configuración de Swagger

Swagger tiene un fichero de cofiguracion en la carpeta config:

  • config/l5-swagger.php En su contendio podemos especificar diferentes directivas, como el directorio dónde se ubica los fichero de anotaciones o especificación general:
1
2
3
4
'paths' => [
            'docs' => storage_path('api-docs'),
            'annotations' => base_path('app/Http/Controllers'),
          ],

Si tu API usa autenticación, puedes configurar el esquema de seguridad:

1
2
3
4
5
6
7
'defaults' => [
      'security' => [
          [
              'bearerAuth' => []
          ],
      ],
],

Incluir informacion sobre el api usando swager

Para incluir información sobre nuestra api, lo realizaremos incluyendo las Etiquetas de swagger o Anotaciones de swagger .

Estas etiquetas se incluyen entre comentarios en el fichero correspondiente usando la forma de comentar

1
2
3
/**
 @OA/anotacion (anotaciones swager)
*/

Las anotaciones más comúnmente usadas son:

Anotación Descripción en Español
@OA\Info Define los metadatos de la API (título, versión, descripción).
@OA\Get Define una petición GET.
@OA\Post Define una petición POST.
@OA\Put Define una petición PUT.
@OA\Delete Define una petición DELETE.
@OA\Schema Define un modelo reutilizable.
@OA\Property Define una propiedad dentro de un esquema.
@OA\Parameter Define un parámetro de consulta o ruta.
@OA\RequestBody Define el cuerpo de una petición (POST/PUT).
@OA\Response Define posibles respuestas.
@OA\JsonContent Define la estructura JSON dentro de una respuesta.
@OA\SecurityScheme Define el método de autenticación (Bearer, API Key).
@OA\Tag Agrupa endpoints bajo una etiqueta.
@OA\Server Define la URL base del servidor.

A continuación mostramos un ejemplo de información general de nuestra API, que habrá que ubicarlo en el fichero del controlador antes de la especificación de la clase

Ejemplo de @OA\Info
<?php

namespace App\Http\Controllers;

use  ...
/**
* @OA\Info(
*     title="API de Alumnos",
*     version="1.0.0",
*     description="Para obtener listado de alumnos",
*     @OA\Contact(
*         name="Manuel",
*         email="manuelromeromiguel@gmail.com"
*     ),
*     @OA\License(
*         name="MIT",
*         url="https://opensource.org/license/mit"
*     )
* )
  */

class AlumnoApiController extends Controller{
.....
  • Una vez escritos las anotaciones, ya las podemos ver en la web, para ello temeos que generar la documentación y acceder a la web donde se ha generado dicha información:
  php artisan l5-swagger:generate
  • Y ahora accedemos a la web.

(debemos tener levantada nuestra aplicación, si estamos en local podemos ejecutar el script dev de composer.json):

1
composer run dev

Y podemos acceder a la información en nuestro navegador

http://127.0.0.1:8000/api/documentation

Incluyendo información general

La información general, debería de ir en un fichero dedicado para esto: app/Http/Swagger.php .

Alternativamente podemos incluirlo directamente el en controlador de la API, y así tener todo concentrado en un solo fichero.

Principales Campos de Metadatos en @OA\Info

Estos son los campos de metadatos u opciones más importantes utilizados en @OA\Info:

Principales Campos en @OA\Info
Campo Descripción en Español Obligatorio
title Define el título de la API.
version Especifica la versión de la API.
description Proporciona una descripción general de la API. No
termsOfService Enlace a los términos de servicio de la API. No
@OA\Contact Información de contacto del responsable de la API. No
@OA\License Detalles sobre la licencia de la API. No

Vemos que tenemos dos componentes o campos de anotación como elementos del componente OA\Info :

Campos dentro de @OA\Contact
Opción Descripción Obligatorio
name Nombre de la persona de contacto. ❌ No
email Dirección de correo electrónico de contacto. ❌ No
url URL con más información de contacto. ❌ No
Campos dentro de @OA\License
Campo Descripción en Español Obligatorio
name Nombre de la licencia de la API.
url Enlace a la licencia de la API. No

🔹 2. Definir Endpoints de la API

Para poder general la información de nuestra apì, al menos tenemos que tener un entrypoint de acceso, si no, no nos generará la documentación

Principales Campos de Metadatos en @OA\Get, @OA\Post, @OA\Put y @OA\Delete

Estos son los campos de metadatos más importantes utilizados en los métodos HTTP dentro de Swagger:

Anotación Descripción en Español Obligatorio
path Define la ruta de la API donde se ejecutará la operación. ✅ Sí
operationId Identificador único de la operación dentro de la API. ✅ Sí
tags Agrupa las operaciones en categorías dentro de la documentación. ❌ No
summary Breve descripción de la operación. ❌ No
description Explicación más detallada de la operación. ❌ No
@OA\Response Define las respuestas esperadas de la API. ✅ Sí
@OA\Parameter Define los parámetros que recibe la API en la URL o query. ✅ Solo si hay parámetros en la URL
@OA\RequestBody Define los datos que se envían en una petición (POST o PUT). ✅ Solo en POST y PUT
@OA\JsonContent Especifica el formato de respuesta en JSON. ✅ Solo si la respuesta es JSON
@OA\Items Define los elementos dentro de una respuesta que es un array. ✅ Solo si la respuesta es un array
@OA\Response
Opción Descripción Obligatorio
response Código de estado HTTP (200, 400, 404, etc.). ✅ Sí
description Breve descripción de la respuesta. ✅ Sí
@OA\JsonContent Define el contenido en formato JSON. ❌ No
@OA\XmlContent Define el contenido en formato XML. ❌ No
@OA\Parameter
Opción Descripción Obligatorio
name Nombre del parámetro (id, page, etc.). ✅ Sí
in Ubicación (query, path, header, cookie). ✅ Sí
required Indica si el parámetro es obligatorio (true o false). ✅ Solo en path
@OA\Schema Define el tipo de dato (string, integer, boolean). ❌ No
@OA\RequestBody
Opción Descripción Obligatorio
required Indica si el cuerpo es obligatorio (true o false). ✅ Sí
description Explicación del contenido del cuerpo. ❌ No
@OA\JsonContent Define el contenido en JSON. ✅ Solo si la petición envía datos
@OA\XmlContent Define el contenido en XML (opcional). ❌ No
@OA\JsonContent
Opción Descripción Obligatorio
type Tipo de dato (object, array). ✅ Sí
@OA\Items Define elementos dentro de un array. ❌ No
@OA\Property Define propiedades dentro de un objeto JSON. ❌ No
@OA\Items
Opción Descripción Obligatorio
type Tipo de dato de los elementos (string, integer, object). ✅ Sí
@OA\Property Define propiedades dentro del objeto del array. ❌ No
example Define un valor de ejemplo para un elemento del array. ❌ No
ref Permite hacer referencia a un esquema predefinido (ref="#/components/schemas/Alumno"). ❌ No
@OA\Property
Opción Descripción Obligatorio
property Nombre de la propiedad en el objeto JSON. ✅ Sí
type Tipo de dato (string, integer, boolean, array, object). ✅ Sí
format Formato del dato (date-time, email, uuid, etc.). ❌ No
example Valor de ejemplo para la propiedad. ❌ No
description Breve explicación de la propiedad. ❌ No
@OA\Items Se usa si la propiedad es un array (type="array"). ❌ No
@OA\Schema Se usa si la propiedad es un objeto (type="object"). ❌ No

Cada método HTTP tiene su propia anotación:

🟢 GET Request (@OA\Get) - Recupera datos

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
/**
* @OA\Get(
*      path="/api/users",
*      operationId="getUsersList",
*      tags={"Users"},
*      summary="Get all users",
*      description="Returns a list of users",
*      @OA\Response(
*          response=200,
*          description="Successful response",
*          @OA\JsonContent(type="array", @OA\Items(ref="#/components/schemas/User"))
*      )
* )
  */
  

🟡 POST Request (@OA\Post) - Crea un nuevo recurso

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
/**
* @OA\Post(
*      path="/api/users",
*      operationId="createUser",
*      tags={"Users"},
*      summary="Create a new user",
*      description="Stores a new user in the database",
*      @OA\RequestBody(
*          required=true,
*          @OA\JsonContent(
*              required={"name","email","password"},
*              @OA\Property(property="name", type="string", example="John Doe"),
*              @OA\Property(property="email", type="string", example="johndoe@example.com"),
*              @OA\Property(property="password", type="string", example="123456")
*          )
*      ),
*      @OA\Response(response=201, description="User created successfully")
* )
  */
  

🔹 3. Definir Modelos de Respuesta (@OA\Schema)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
/**
* @OA\Schema(
*     schema="User",
*     type="object",
*     required={"id", "name", "email"},
*     @OA\Property(property="id", type="integer", example=1),
*     @OA\Property(property="name", type="string", example="John Doe"),
*     @OA\Property(property="email", type="string", example="johndoe@example.com")
* )
  */
  

🔹 4. Autenticación (@OA\SecurityScheme)

1
2
3
4
5
6
7
8
9
/**
* @OA\SecurityScheme(
*      securityScheme="bearerAuth",
*      type="http",
*      scheme="bearer",
*      bearerFormat="JWT"
* )
  */
  

🔹 Documentar el método index

Edita app/Http/Controllers/Api/UserController.php y agrega las anotaciones de Swagger:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
namespace App\Http\Controllers\Api;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

/**
* @OA\Get(
*      path="/api/users",
*      operationId="getUsersList",
*      tags={"Usuarios"},
*      summary="Obtener lista de usuarios",
*      description="Retorna una lista de usuarios",
*      @OA\Response(
*          response=200,
*          description="Éxito",
*          @OA\JsonContent(
*              type="array",
*              @OA\Items(
*                  type="object",
*                  @OA\Property(property="id", type="integer", example=1),
*                  @OA\Property(property="name", type="string", example="Juan Pérez"),
*                  @OA\Property(property="email", type="string", example="juan@example.com")
*              )
*          )
*      )
* )
  */
  class UserController extends Controller
  {
  public function index()
  {
  return response()->json([
  ['id' => 1, 'name' => 'Juan Pérez', 'email' => 'juan@example.com'],
  ['id' => 2, 'name' => 'Ana Gómez', 'email' => 'ana@example.com'],
  ]);
  }
  }
  

🔹 Generar y visualizar la documentación

Ejecuta el siguiente comando para generar la documentación:

1
php artisan l5-swagger:generate

Luego, inicia el servidor:

1
php artisan serve

Y accede a la documentación desde el navegador:

http://127.0.0.1:8000/api/documentation

🔹 Conclusión

Con estos pasos, has configurado Swagger en Laravel 11 y documentado el primer endpoint (index). Puedes continuar documentando otros métodos como store, update y destroy siguiendo la misma estructura.