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)
REST
REST
en seis principios fundamentales
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
Recurso
Un recurso es información que está en el servidor a la cual vamos a poder acceder a través de una url
ej: http://localhost:8000/alumnos
alumnos es un recurso
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
Instalamos el paquete
composer require laravel-shift/blueprint --dev
Creamos el fichero de especificación de construcción
php_ artisan blueprint:new
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
Modificamos previa publicación opciones de blueprint
Primero publicamos
php_ artisan vendor:publish
2. Ahora modificamos el fichero generado en
config/blueprint.yaml
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
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
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
En este caso el método delete es muy sencillo. Podemos retornar un mensaje
1
2
3
4
5
publicfunctiondestroy(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
publicfunctiontest_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
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.
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
*/publicfunctioncan_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
*/publicfunctioncan_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,
/**
* @test
*/publicfunctioncan_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
*/publicfunctioncan_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();
}
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.
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:
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
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.
✅ Sí
version
Especifica la versión de la API.
✅ Sí
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.
✅ Sí
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"))
* )
* )
*/
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.