laravel-rest lanza 470 escenarios contra 62 APIs públicas para ver si el patrón aguanta
El autor de este paquete de Laravel lo ha probado contra 62 APIs públicas con peticiones reales, para ver si su abstracción estilo Eloquent aguanta fuera de los casos cómodos.

El autor de laravel-rest, un paquete que da a las APIs externas el mismo aspecto que un modelo Eloquent, ha sometido su invento a una prueba de esfuerzo: 62 APIs públicas, 470 escenarios y una ejecución nocturna con peticiones de verdad, sin mocks. Quería comprobar si la uniformidad que promete el paquete es real o solo fruto de haber probado con APIs elegidas a dedo.
Por qué quiso hacerlo
En su trabajo tenía que hablar con muchas APIs externas desde Laravel, y cada una arrastraba su propio cliente, su bucle de paginación y su manera particular de decir "no encontrado". Quería que Post::where(...)->paginate(), que ya conocía, funcionase contra todas ellas. Después dedicó tiempo al rendimiento —eager loading, peticiones concurrentes, memoization— y le entró la duda: ¿el patrón se sostiene o solo lo parece?
Así que montó un catálogo de APIs públicas escogidas por estructura, no por temática: paginación por página, por offset y por cursor; respuestas con array pelado y con todas las formas de envelope; JSON:API, OData, Socrata, GraphQL y JSON-RPC.
Lo que devolvió el cable
PokéAPI es el caso llano. El modelo declara dónde están las filas (dataKey apuntando a results) y que la clave primaria es el nombre; la configuración del cliente indica paginación por offset, con el total en count y el siguiente en next. Una petición, y devuelve un LengthAwarePaginator, la misma clase que entrega Eloquent: total 1351, última página 451 y primer elemento con nombre "bulbasaur".
El Art Institute of Chicago añade envelope y clave foránea. El modelo apunta a data y declara una relación belongsTo sobre artist_id. El envoltorio desaparece: los bloques info y config nunca llegan al modelo. Pidiendo dos obras con with('artist') salen tres peticiones en el cable, la lista y los dos artistas a la vez, no una por artista.
El mismo código sirve en crates.io, donde el tamaño de página se llama per_page y el total vive en meta.total; basta con mapearlo en la configuración.
El query builder se traduce según la gramática que se le asigne al cliente. Un where() y un orderBy() acaban en el cable como ?document__slug=kp,dmag-e&sort=name en formato plano, ?filter[document__slug]=...&sort=name en JSON:API, ?document__slug__in=...&ordering=name en Django —Open5e, Spaceflight News—, $filter y $orderby en OData, o fq=license_id:cc-by&sort=name asc en CKAN. Algunas de esas gramáticas son clases propias de unas 30 líneas.
En la parte de rendimiento el autor avisa de que los números son ejecuciones sueltas en su portátil y de que las peticiones las contó un middleware de historial de Guzzle. La carga perezosa le da el N+1 de manual: cuatro obras con cuatro artistas distintos se resuelven con cinco peticiones encadenadas.
Las conclusiones detalladas quedan en el registro de la verificación en vivo, con las APIs y los escenarios empleados. Eso es lo útil aquí: quien tenga que integrar media docena de servicios con formas distintas de paginar puede ver de antemano qué espera el paquete de cada uno y qué hace cuando la respuesta no encaja. Lo que no hay es una demo pública del conjunto, solo la traza de las ejecuciones y el código.