https://a.storyblok.com/f/270183/1368x665/5601fd767f/26apr_dev-blog_rapid-api-development.jpg

Desarrollo rápido de API con Laravel y API Platform

Publicado el April 28, 2026

Tiempo de lectura: 7 minutos

Es la opinión personal de este autor que más gente fuera del espacio PHP debe saber acerca de Plataforma API. Es una asombroso pieza de kit que puede estructurar toda su aplicación web API en 10 minutos para empezar, y viene con una vertiginosa variedad de características que va a transformar y manejar la autenticación dentro de su aplicación cambiando los interruptores de configuración.

En este artículo, tomaremos una aplicación Laravel existente que utiliza Messages API de Vonage y la abriremos como una API web bajo varios estándares.

¿Qué es una plataforma API?

Bien, esta es la parte un poco confusa: La Plataforma API es un framework PHP, pero ese framework se asienta sobre Symfony o Laravel (que también incluye otros frameworks y plataformas que se construyen sobre ellos, como por ejemplo Drupal o WinterCMS). Piense en ello como un conjunto de configuraciones y atributos que puede agregar a su modelado de base de datos y la carpeta config. También viene con un tablero web completo incorporado, para pruebas con herramientas API como Postman y OpenAPI y OpenAPI.

Arrancar una aplicación Laravel existente

AKA. "¡Aquí hay uno que hice antes!" Vamos a utilizar una aplicación que sólo tiene una entidad de base de datos: el humilde ToDo, que codifiqué en un artículo anterior. También utiliza la Mensajes API de Vonage para enviar el contenido de texto de ToDo a un dispositivo configurado cuando se marca uno de los elementos de ToDo (actuando como una notificación). Debido a que es una aplicación en pleno funcionamiento, vamos a empezar por arrancar esta aplicación antes de agregarle la Plataforma API.

TLDR; puedes encontrar el código fuente aquí.

Requisitos previos

  • git

  • PHP 8.3+

  • Node 23+ y npm

  • Compositor

  • Una Account de Vonage

Configuración de la aplicación web

  1. Obtenga el repositorio en su máquina: https://github.com/Vonage-Community/blog-messages_native_php

  2. Instalar dependencias: composer install

  3. Ejecutar migraciones en la línea de comandos: php artisan migrate

  4. Ejecute npm en la línea de comandos: npm i

  5. En la línea de comandos, ejecute Vite con npm run dev

  6. En la línea de comandos, ejecute el sembrador de base de datos para obtener algunos datos en nuestra aplicación: php artisan db:seed

  7. Copie el ejemplo .env para convertirlo en .env en la línea de comandos: cp .env.example .env

  8. Agrega tus credenciales de Vonage al archivo .env archivo.

Esta aplicación utiliza la API Messages API de Vonage para enviar un SMS cuando se completa la tarea, por lo que necesitarás crear una cuenta de Vonage y luego crear una aplicación de Vonage. Al crear la aplicación, selecciona la funcionalidad Mensajes, completa los campos de webhooks con datos ficticios y anota el icono application_id al momento de la creación. Mueve el private.key que se descarga automáticamente a la raíz de los archivos de tu proyecto.

  • Para crear una aplicación, vaya a la sección Crear una aplicación en el panel de Vonage y define un nombre para tu aplicación.

  • Si tiene intención de utilizar una API que utilice Webhooks, necesitará una clave privada. Haga clic en "Generar clave pública y privada"; la descarga debería iniciarse automáticamente. Guárdela de forma segura; esta clave no puede volver a descargarse si se pierde. Seguirá la convención de nomenclatura private_<id de su aplicación>.key. Esta clave puede utilizarse ahora para autenticar llamadas a la API. Nota: La clave no funcionará hasta que se guarde la aplicación.

  • Elija las funciones que necesite (por ejemplo, Voice, Messages, RTC, etc.) y proporcione los webhooks necesarios (por ejemplo, URL de eventos, URL de respuestas o URL de mensajes entrantes). Estos se describirán en el tutorial.

  • Para guardar e implementar, haz clic en "Generar nueva aplicación" para finalizar la configuración. Tu aplicación ahora está lista para usar con las API de Vonage.

En el archivo .env tendrás que añadir tu configuración:

VONAGE_APPLICATION_ID="<YOUR_APPLICATION_ID_HERE>"
VONAGE_PRIVATE_KEY_PATH="./private.key"
VONAGE_TO="<YOUR-NUMBER-HERE>"

Tenga en cuenta que VONAGE_PRIVATE_KEY_PATH debe tener siempre el valor indicado anteriormente, ya que la aplicación resolverá la lectura de su clave privada en el nivel raíz.

VONAGE_TO es el número al que desea que se envíe la notificación por SMS.

Necesitarás servir tu aplicación. Recomiendo usar Laravel Herd. Puedes encontrar las instrucciones de instalación aquí. Alternativamente, puede ejecutar el servidor PHP integrado desde la línea de comandos: php artisan serve

Screenshot showing the main page of the ToDo appApp up and running!

El enigma: de MVC a API

La aplicación está escrita como una clásica aplicación Modelo-Vista-Controlador con una pizca de magia frontend cortesía de Laravel Livewire. Sin embargo, consideremos dos escenarios:

  1. Queremos conectar herramientas externas a nuestra aplicación, por lo que necesitaremos exponer una API.

  2. El escalado masivo significa que tenemos que desacoplar los extremos frontal y posterior, lo que significa que tenemos un marco de JavaScript independiente, como Svelte o Vue, que consume y envía datos a la API expuesta.

La increíble experiencia de la plataforma API

Es hora de instalar la Plataforma API. Abre tu terminal y añade lo siguiente:

composer require api-platform/laravel

Todavía en el terminal, termina la instalación con la consola.

php artisan api-platform:install

Eso es todo para la instalación. ¿No me crees? Dirígete a la URL de tu proyecto y añade /api:

Screenshot of the API Platform landing pageWe've certainly done -something-Tenemos un modelo ORM de Eloquent, Todo. Se ve así en la aplicación:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Todo extends Model
{
   /**
    * The attributes that are mass assignable.
    *
    * @var array<int, string>
    */

   protected $fillable = [
       'title',
       'completed',
   ];

   /**
    * The attributes that should be cast.
    *
    * @var array<string, string>
    */

   protected $casts = [
       'completed' => 'boolean',
   ];
}

¿Estás preparado? El siguiente paso lo cambiará todo, y te explicaré lo que ocurre después. Añade este atributo:

<?php

namespace App\Models;

use ApiPlatform\Metadata\ApiResource;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

#[ApiResource]
class Todo extends Model
{
   use HasFactory;

   /**
    * The attributes that are mass assignable.
    *
    * @var array<int, string>
    */

   protected $fillable = [
       'title',
       'completed',
   ];

   /**
    * The attributes that should be cast.
    *
    * @var array<string, string>
    */
   protected $casts = [
       'completed' => 'boolean',
   ];
}

OK, he añadido #[ApiResource]. ¿Y eso qué hace? Refresca el directorio /api/ dashboard:

Screenshot showing HTTP routes for a ToDo entityAn OpenAPI document renders our new magic APIEh, ¿vale? Entonces, ¿qué, ahora tenemos un conjunto completo de rutas REST? Supongo que debería comprobarlo. En la base de datos, tenemos 10 accesorios, así que vamos a ver qué pasa si uso HTTPie para lanzar el comando GET{id} para obtener la entrada 5 (además: ¡nunca expongas tus claves primarias en tu base de datos en el mundo real!)

A screenshot of HTTPie returning a 200 of a ToDo entity in JSON-LD formatAbsolute cinema!¿Eh? ¿Acabas de... hacer una API para mí? ¿Qué tal si envío una PATCH solicitud para editar el título?

Screenshot showing that the ToDo app now has REST API endpoints with an API response in HTTPieSuddenly, a wild REST API appearsDE ACUERDO. Hemos añadido dos líneas de código, y tenemos una API. Eso es bastante salvaje.

Profundizando: Normas API y paginación

Los más avispados se habrán dado cuenta de que la Plataforma API ha adoptado por defecto un patrón de estructura de datos, con campos denominados @contexto y @id. Pero, ¿por qué los campos tienen este aspecto?

La respuesta es que la Plataforma API utiliza por defecto el formato formato JSON-LD (JSON For Linking Data). Puede que estemos viendo sólo una entidad aquí, pero si tuviéramos una relación de entidad uno-a-muchos, la Plataforma API manejaría automáticamente los resultados devueltos por usted. Añadamos, como ejemplo, una nueva entidad llamada SubTask. En Eloquent, la relación tendría este aspecto:

   public function subtasks(): HasMany
   {
       return $this->hasMany(Subtask::class);
   }

Llamando al mismo endpoint se obtendría una respuesta como la siguiente. Ten en cuenta que he añadido el código de Serialización de Grupos que determina qué campos mostrar. Puedes leer sobre la serialización de la plataforma API aquío, en el caso concreto de Laravel, utilizar la configuración de array $visible para exponer qué partes del modelo quieres renderizar.

{
    "@context": "/api/contexts/Todo",
    "@id": "/api/todos/5",
    "@type": "Todo",
    "id": 5,
    "title": "sample patch request",
    "completed": false,
    "createdAt": "2026-03-10T13:44:23+00:00",
    "updatedAt": "2026-03-11T11:41:13+00:00",
    "subTasks": [
        {
            "@id": "/api/sub_tasks/1",
            "@type": "SubTask",
            "id": 1,
            "title": "Write request body",
            "completed": true
        },
        {
            "@id": "/api/sub_tasks/2",
            "@type": "SubTask",
            "id": 2,
            "title": "Send PATCH request",
            "completed": false
        },
        {
            "@id": "/api/sub_tasks/3",
            "@type": "SubTask",
            "id": 3,
            "title": "Verify API response",
            "completed": false
        }
    ]
}

¿No es genial que la Plataforma API se ocupe de los datos de tu API por ti? ¡Parece que es hora de deshacerse de todas esas capas de transformación y DTOs!

Pero, espera: ¿qué pasa si mi estándar de elección para el desarrollo REST no es JSON-LD? Es entonces cuando nos dirigimos a la configuración, que se puede encontrar en configuration/api-platform.php.

<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

use ApiPlatform\Metadata\UrlGeneratorInterface;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\AuthenticationException;
use Symfony\Component\Serializer\NameConverter\SnakeCaseToCamelCaseNameConverter;

return [
   'title' => 'API Platform',
   'description' => 'My awesome API',
   'version' => '1.0.0',
   'show_webby' => true,
   'routes' => [
       'domain' => null,
       // Global middleware applied to every API Platform routes
       // 'middleware' => [],
   ],
   'resources' => [
       app_path('Models'),
   ],
   'formats' => [
       'jsonld' => ['application/ld+json'],
       // 'jsonapi' => ['application/vnd.api+json'],
       // 'csv' => ['text/csv'],
   ],

(Dejé el Copyright ahí sólo para dar a Kevin Duglas un saludo).

¿Ves que hay una formats en el array config? Vamos a cambiar eso:

   'formats' => [
       'jsonld' => ['application/ld+json'],
       'jsonhal' => ['application/hal+json'],
   ],

Si vuelves a enviar la petición, nada cambia. Sigue en JSON-LD. ¿Por qué?

Esto forma parte de la implementación de la Negociación de Contenidos de la Plataforma API. LD-JSON sigue siendo el primera por defecto. Pero, cambie las cabeceras de su solicitud a accept: application/hal+json y lance la solicitud:

Screenshot of the response, but now formatted in HALSuddenly, a wild HAL appearsAsí que ahora el poder está en manos de los consumidores de su API, ya que pueden solicitar el formato que deseen.

También le da a usted, el autor de su API, el tipo de poder alucinante para crear un nuevo punto final en su aplicación, por ejemplo. /api/v2, y simplemente cambiarlo. Volvámonos locos: ¿y si sólo queremos cambiar nuestra API por una GraphQL? Sí. Puedes hacerlo en sólo ¡3 pasos!

  1. Instalar la Plataforma API GraphQL con Composer en el navegador

composer require api-platform/graphql
  1. Active GraphQL en su configuration/api-platform.php archivo

   'graphql' => [
       'enabled' => true,
       'nesting_separator' => '__',
       'introspection' => ['enabled' => true],
       'max_query_complexity' => 500,
       'max_query_depth' => 200,
       // 'middleware' => null,
   ],
  1. Dirígete a /api/graphql ¿y qué ocurre?

Screenshot of the built-in API Platform GraphQL sandboxA Built-in GraphQL sandbox, just for youSí, así es. Tienes un patio de juegos GraphQL porque tu API ahora es GraphQL. Si no me crees:

Screenshot of an API call returning a GraphQL responseFrom REST to GraphQL in mere minutesAhora tiene una API GraphQL y una API REST.

La paginación es una de esas cosas que siempre me ha parecido un dolor muy manual de implementar. API Platform tiene un enfoque que raya en lo ridículo cuando se trata de simplificar el proceso de integración de la paginación. Considere nuestro modelo ToDo de nuevo:

<?php

namespace App\Models;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Symfony\Component\Serializer\Attribute\Groups;

#[ApiResource(normalizationContext: ['groups' => ['read']])]
#[ApiProperty(property: 'title', serialize: [new Groups(['read'])])]
#[ApiProperty(property: 'completed', serialize: [new Groups(['read'])])]
class Todo extends Model
{
   use HasFactory;

   /**
    * Get the subtasks for the todo.
    */
   #[ApiProperty(readableLink: true)]
   #[Groups(['read'])]
   public function subtasks(): HasMany
   {
       return $this->hasMany(Subtask::class);
   }

   /**
    * The attributes that are mass assignable.
    *
    * @var array<int, string>
    */

   protected $fillable = [
       'title',
       'completed',
   ];

   /**
    * The attributes that should be cast.
    *
    * @var array<string, string>
    */
   protected $casts = [
       'completed' => 'boolean',
   ];
}

He añadido nuevos atributos que son para dar formato a la Subtask relación. Para añadir la paginación, voy a establecer un valor predeterminado para el número de entidades devueltas por página, a continuación, probar el page URL cadena de consulta. Añadir el siguiente atributo a la clase:

#[ApiProperty(property: 'title', serialize: [new Groups(['read'])])]
#[ApiProperty(property: 'completed', serialize: [new Groups(['read'])])]
#[ApiResource(
   normalizationContext: ['groups' => ['read']],
   paginationItemsPerPage: 5,
)]
#[ApiProperty(property: 'title', serialize: [new Groups(['read'])])]
#[ApiProperty(property: 'completed', serialize: [new Groups(['read'])])]
class Todo extends Model

Y ya está. Hecho. Como tenemos 10 Todos, eso significa que deberíamos tener dos páginas-5 entidades devueltas por página. Así que, puedes probar añadiendo la página 2:

Screenshot of an API call showing pagination standard fields rendered by API PlatformMagical pagination out of the boxTambién ha añadido enlaces de paginación, magia.

Conclusión

Una de las cosas que dije cuando hablé de la potencia de la Plataforma de APIs en la Conferencia de la Plataforma de APIs 2025 fue que los desarrolladores de PHP que utilizan este framework día tras día probablemente no son conscientes de lo poco frecuente que es este tipo de potencia. No he encontrado nada más que pueda poner este tipo de funciones en manos de los desarrolladores y hacerlo tan sencillo. Si no perteneces al mundo PHP, pruébalo, ha hecho que el desarrollo de APIs vuelva a ser divertido para mí.

¿Tiene alguna pregunta o quiere compartir lo que está construyendo?

Mantente conectado y entérate de las últimas noticias, consejos y eventos para desarrolladores.

Compartir:

https://a.storyblok.com/f/270183/400x385/12b3020c69/james-seconde.png
James SecondePromotor senior de desarrollo PHP

Actor de formación con una disertación sobre la comedia, llegué al desarrollo de PHP a través de la escena de las reuniones. Puedes encontrarme hablando y escribiendo sobre tecnología, o tocando/comprando discos raros de mi colección de vinilos.