Lección 1 de 415 min
Paradigmas de API
REST, GraphQL, SOAP, gRPC, JSON-RPC, XML-RPC y JSON:API: qué propone cada uno y cuándo encaja.
Tu app de blog tiene una pantalla de perfil que necesita el nombre de la autora, su avatar y los títulos de sus tres últimos posts. Con una API, la pantalla hace dos peticiones y recibe treinta campos que no usa; con otra, una sola petición trae justo lo necesario. Un servicio interno, en cambio, prefiere llamar a una función remota y recibir datos binarios muy compactos. Las tres APIs sirven para lo mismo, pero no proponen lo mismo.
En la lección «Tiempo real y estilos de API» del módulo 1 viste cómo viaja cada protocolo. Aquí vamos un paso más allá: cómo se diseña una API con cada paradigma, qué problemas resuelve cada uno y qué precio pagas al elegirlo.
Recursos y consultas: REST, JSON:API y GraphQL
REST organiza la API alrededor de recursos con su propia URL; GraphQL, alrededor de un esquema que el cliente consulta pidiendo los campos que quiere. JSON:API se queda en medio: es REST, pero con unas reglas comunes que resuelven parte de los problemas que motivaron GraphQL.
REST
Recursos con URL propia, manipulados con los verbos y códigos de HTTP.
- Tipo:
- Estilo de arquitectura
- Propuesto por:
- Roy Fielding
- Desde:
- 2000
REST es un estilo de arquitectura, no un protocolo: lo describió Roy Fielding en su tesis doctoral en el año 2000. Cada cosa que expone la API es un recurso con su URL (/usuarios/7, /usuarios/7/posts), y los verbos de HTTP dicen qué hacer con él: GET para leer, POST para crear, PUT o PATCH para modificar y DELETE para borrar. Los códigos de estado cuentan el resultado: 201 Created, 404 Not Found, 409 Conflict.
Es sin estado (stateless): cada petición lleva todo lo necesario para atenderla, incluido el token de autenticación, y el servidor no recuerda nada de las anteriores. Eso permite repartir las peticiones entre muchos servidores y aprovechar la caché de HTTP, porque un GET a la misma URL debería devolver lo mismo.
La versión más estricta añade HATEOAS: cada respuesta incluye enlaces a las acciones posibles, como en una página web, para que el cliente navegue la API sin conocer las URLs de antemano. Pocas APIs reales lo aplican del todo.
Úsalo cuando
Para APIs públicas y operaciones de crear, leer, modificar y borrar. Cualquier lenguaje y herramienta la entiende, incluido curl, y las respuestas a GET se pueden cachear en un CDN.
Ten en cuenta
Cada endpoint devuelve una forma fija: una pantalla puede recibir campos que no usa (over-fetching) o necesitar varias peticiones para reunir lo que le falta (under-fetching). Y como REST no es un estándar, muchas APIs que se llaman REST son solo «JSON sobre HTTP».
POST /usuarios/7/posts HTTP/1.1
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...
{ "titulo": "Grid sin miedo" }
HTTP/1.1 201 Created
Location: /posts/58
Content-Type: application/json
{
"id": 58,
"titulo": "Grid sin miedo",
"_links": { "autora": { "href": "/usuarios/7" } }
}JSON:API
Una especificación que fija cómo deben ser las respuestas JSON de una API REST.
- Tipo:
- Convención para REST
- Tipo MIME:
- application/vnd.api+json
Cada API REST decide a su manera dónde van los datos, cómo se pagina o cómo se piden los recursos relacionados. JSON:API es una especificación que lo deja todo acordado: cada recurso va en data con su type y su id, sus campos en attributes y sus vínculos con otros recursos en relationships.
Dos parámetros resuelven buena parte del over- y el under-fetching sin salir de REST: include incrusta los recursos relacionados en la misma respuesta, dentro de included, y los sparse fieldsets (fields[tipo]=campo1,campo2) limitan los campos que vuelven. También define cómo ordenar (sort), paginar (page) y devolver errores.
Úsalo cuando
Cuando tu equipo pierde tiempo debatiendo el formato de cada endpoint, o quieres usar bibliotecas cliente genéricas que ya conocen la estructura.
Ten en cuenta
Es más verboso que un JSON a medida, y los id siempre son texto ("7", no 7). No basta con que el servidor lo siga: el cliente también tiene que entender la estructura, con su tipo de contenido propio, application/vnd.api+json.
{
"data": {
"type": "posts",
"id": "58",
"attributes": { "titulo": "Grid sin miedo" },
"relationships": {
"autora": { "data": { "type": "usuarios", "id": "7" } }
}
},
"included": [
{ "type": "usuarios", "id": "7", "attributes": { "nombre": "Ana Torres" } }
]
}GraphQL
Un solo endpoint y un esquema de tipos: el cliente pide exactamente los campos que quiere.
- Creado por:
- Facebook (Meta)
- Público desde:
- 2015
- Mantiene:
- GraphQL Foundation
GraphQL nació en Facebook y se publicó en 2015; hoy lo mantiene la GraphQL Foundation. La API se describe con un esquema de tipos (lo verás en la lección «GraphQL SDL» del módulo de lenguajes) y se expone en una única URL, normalmente /graphql. El cliente envía una consulta que enumera los campos que necesita, y la respuesta tiene exactamente esa forma.
Así desaparecen el over-fetching, porque no llega ningún campo que no hayas pedido, y el under-fetching, porque en una sola consulta puedes atravesar relaciones: el usuario, sus posts y los comentarios de cada post. Las escrituras se hacen con mutaciones y el tiempo real con suscripciones, que verás en la próxima lección.
En el servidor, cada campo lo resuelve una función (un resolver). Si pides 20 posts con su autor y cada resolver de autor consulta la base de datos por separado, haces 1 + 20 consultas: el problema N+1. La solución habitual es agrupar esas búsquedas en una sola, con herramientas como DataLoader.
Úsalo cuando
Cuando varias apps (web, móvil) muestran los mismos datos de formas distintas y quieres que el frontend evolucione sin pedir un endpoint nuevo para cada pantalla.
Ten en cuenta
La caché de HTTP casi no ayuda, porque las consultas suelen ir por POST a la misma URL: la caché se hace en el cliente o con consultas persistidas. Muchos servidores responden 200 OK aunque haya errores, que llegan en un campo errors. Y limita la profundidad y el coste de las consultas para que nadie sature el servidor con una consulta gigante.
query Perfil {
usuario(id: 7) {
nombre
avatar
posts(ultimos: 3) {
titulo
}
}
}
# La respuesta tiene la misma forma que la consulta:
# { "data": { "usuario": { "nombre": "Ana Torres", "avatar": "…",
# "posts": [{ "titulo": "Grid sin miedo" }, …] } } }Pruébalo
En el simulador, empieza en REST y cuenta cuántos valores llegan sin usarse. Luego pasa a GraphQL y marca solo los campos que necesita la pantalla. Después marca alguno de más: el over-fetching también se puede provocar a mano.
Interactivo
Pedir datos con REST y con GraphQL
Una pantalla de perfil necesita el nombre, el avatar y los títulos de los 3 últimos posts. Compara qué viaja por la red con cada enfoque.
1
GET /usuarios/7200 OK · 277 bytes{ "id": 7, "nombre": "Ana Torres", "usuario": "anatorres", "email": "ana@ejemplo.com", "avatar": "https://cdn.ejemplo.com/avatares/7.png", "bio": "Desarrolladora web. Escribo sobre CSS y accesibilidad.", "ciudad": "Valencia", "seguidores": 1284, "siguiendo": 311, "creado": "2021-03-14T09:30:00Z"}2
GET /usuarios/7/posts200 OK · 776 bytes[ { "id": 58, "titulo": "Grid sin miedo", "extracto": "Cinco patrones de maquetación que uso a diario.", "publicado": "2026-10-30", "likes": 87, "etiquetas": ["css","grid"] }, { "id": 54, "titulo": "Contraste y color", "extracto": "Cómo elegir colores accesibles sin adivinar.", "publicado": "2026-10-12", "likes": 64, "etiquetas": ["accesibilidad"] }, { "id": 51, "titulo": "Formularios que no frustran", "extracto": "Mensajes de error claros y a tiempo.", "publicado": "2026-09-28", "likes": 102, "etiquetas": ["ux","html"] }, { "id": 47, "titulo": "Mi editor, paso a paso", "extracto": "Atajos y extensiones que me ahorran tiempo.", "publicado": "2026-09-02", "likes": 41, "etiquetas": ["herramientas"] }, { "id": 42, "titulo": "Hola, mundo", "extracto": "Por qué abro este blog.", "publicado": "2026-08-15", "likes": 23, "etiquetas": [] }]
Estas dos peticiones pueden ir en paralelo porque ya conoces el id. Si la segunda dependiera de un dato de la primera, irían una detrás de otra y las esperas se sumarían.
Lo que usa la pantallaViaja sin usarse
Resumen: cuerpo JSON de las respuestas, sin espacios ni cabeceras
- REST2 peticiones1053 B
- GraphQL1 petición44 B
REST: 2 peticiones · GraphQL: 1 petición, aunque la consulta también viaja: 66 bytes de subida en el cuerpo del POST.
La pantalla usa 5 de los 40 valores que llegan: el resto es over-fetching. Y como ningún endpoint da todo lo que necesita, haces 2 peticiones (under-fetching). Prueba a paginar con ?limite=3.
Llamar a funciones remotas: XML-RPC, SOAP, JSON-RPC y gRPC
RPC significa «Remote Procedure Call»: llamar a una función que vive en otra máquina como si fuera local. En lugar de pensar en recursos, piensas en acciones: obtenerPost(42), consultarSaldo(cuenta). Estos cuatro protocolos son la historia de esa idea, del XML de finales de los 90 al binario de hoy.
XML-RPC
El abuelo de los RPC web: una llamada a función escrita en XML y enviada por POST.
- Desde:
- 1998
- Formato:
- XML
XML-RPC apareció en 1998 con una idea sencilla: enviar por POST un documento XML <methodCall> con el nombre del método y sus parámetros, y recibir un <methodResponse> con el resultado o un <fault> con el error. Solo tiene unos pocos tipos: enteros, textos, booleanos, decimales, fechas, binario en base64, estructuras y listas.
Es el antecesor directo de SOAP, que lo amplió con todo lo que le faltaba. Hoy apenas se usa en proyectos nuevos, pero sigue vivo en sistemas veteranos: WordPress, por ejemplo, todavía expone un xmlrpc.php.
Úsalo cuando
Solo cuando te integras con un sistema que ya lo usa. Para algo nuevo, JSON-RPC ofrece el mismo modelo con menos ceremonia.
Ten en cuenta
Los endpoints XML-RPC olvidados son un objetivo clásico de ataques: el xmlrpc.php de WordPress se ha usado para probar contraseñas en masa. Si no lo necesitas, desactívalo.
<?xml version="1.0"?>
<methodCall>
<methodName>blog.obtenerPost</methodName>
<params>
<param><value><int>42</int></value></param>
</params>
</methodCall>SOAP
Mensajes XML con sobre, un contrato WSDL y estándares para seguridad y fiabilidad.
- Mantiene:
- W3C
- Contrato:
- WSDL
- Formato:
- XML
En SOAP, cada mensaje es un documento XML con un sobre (Envelope) que contiene una cabecera opcional (Header) y un cuerpo (Body) con la operación y sus datos. Los errores llegan como un Fault. Es un estándar del W3C y casi siempre viaja por HTTP, aunque admite otros transportes.
Su pieza central es el WSDL, un documento XML que describe las operaciones, los tipos de datos (con esquemas XSD) y la dirección del servicio. A partir de él, las herramientas generan el código cliente. Alrededor creció la familia de estándares WS-*: WS-Security, por ejemplo, firma y cifra partes del mensaje dentro del propio XML, de modo que la protección no depende solo de HTTPS y sobrevive a los intermediarios.
Úsalo cuando
Cuando la otra parte lo exige: banca, seguros, administraciones públicas y sistemas empresariales veteranos, donde el contrato estricto y la seguridad a nivel de mensaje son requisitos.
Ten en cuenta
Es verboso y depurarlo a mano cuesta: casi siempre necesitarás herramientas que generen el cliente desde el WSDL. Todo va por POST, así que no hay caché de HTTP. Para una API nueva rara vez es la primera opción.
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<!-- Aquí iría WS-Security: firma, token, marca de tiempo… -->
</soap:Header>
<soap:Body>
<ConsultarSaldo xmlns="https://banco.example/cuentas">
<numeroCuenta>12345678</numeroCuenta>
</ConsultarSaldo>
</soap:Body>
</soap:Envelope>JSON-RPC
Llamadas a métodos en JSON: método, parámetros e id. Y poco más.
- Versión:
- 2.0
- Transporte:
- Cualquiera
JSON-RPC 2.0 es una especificación diminuta. Una petición es un objeto con jsonrpc: "2.0", el method, sus params y un id; la respuesta trae el mismo id y un result o un error con código y mensaje. No le importa el transporte: funciona sobre HTTP, WebSocket o la entrada y salida estándar de un proceso.
Una petición sin id es una notificación: el servidor la ejecuta, pero no responde. Y puedes enviar un lote (batch): un array de peticiones que vuelve como un array de respuestas, que relacionas por su id porque pueden llegar en cualquier orden.
Su sencillez explica dónde aparece: los nodos de Ethereum, el Language Server Protocol con el que tu editor habla con los analizadores de código y el Model Context Protocol (MCP) de los asistentes de IA usan JSON-RPC.
Úsalo cuando
Cuando tu API es una lista de acciones más que de recursos, o cuando dos procesos hablan por un canal que no es HTTP, como un WebSocket o stdio.
Ten en cuenta
No define autenticación, ni caché, ni cómo documentar los métodos (existe OpenRPC para eso). Sobre HTTP, todo va por POST a una misma URL y el resultado real está en el cuerpo, no en el código de estado.
→ Petición
[
{ "jsonrpc": "2.0", "method": "sumar", "params": [2, 3], "id": 1 },
{ "jsonrpc": "2.0", "method": "registrarVisita", "params": { "pagina": "/inicio" } }
]
← Respuesta: la notificación (sin id) no recibe nada
[
{ "jsonrpc": "2.0", "result": 5, "id": 1 }
]gRPC
RPC binario sobre HTTP/2, con un contrato .proto y streaming en ambos sentidos.
- Creado por:
- Formato:
- Protocol Buffers
- Transporte:
- HTTP/2
gRPC lo creó Google y lo publicó como código abierto en 2015. Los servicios y sus mensajes se definen en un archivo .proto con Protocol Buffers, y un compilador genera el cliente y el servidor en muchos lenguajes: llamas a cliente.ObtenerPost({ id: 42 }) como a cualquier función. Los mensajes viajan en un formato binario compacto, mucho más pequeño y rápido de procesar que el JSON equivalente.
Funciona sobre HTTP/2, que permite muchas llamadas a la vez por una misma conexión y streaming: además de la llamada simple, el servidor puede enviar una serie de respuestas, el cliente una serie de peticiones, o ambos a la vez.
Los navegadores no dejan a JavaScript controlar HTTP/2 al nivel que gRPC necesita, así que una web no puede llamar directamente a un servicio gRPC. Para eso existe gRPC-Web: el navegador usa una variante compatible y un proxy, como Envoy, la traduce.
Úsalo cuando
Entre microservicios internos, con mucho tráfico y equipos en lenguajes distintos que quieren un contrato estricto y código generado. También para streaming entre servidores o con apps móviles.
Ten en cuenta
El binario no se lee a simple vista: necesitas herramientas específicas para depurar. Los números de campo del .proto son el contrato: nunca reutilices uno que ya borraste, o los clientes antiguos interpretarán mal los datos.
syntax = "proto3";
service Posts {
// Llamada simple: una petición, una respuesta
rpc ObtenerPost (PostId) returns (Post);
// Streaming desde el servidor: envía cada post nuevo de una autora
rpc SeguirAutora (UsuarioId) returns (stream Post);
}
message PostId { int64 id = 1; }
message UsuarioId { int64 id = 1; }
message Post {
int64 id = 1;
string titulo = 2; // el número identifica el campo en el binario
int64 autora_id = 3;
}¿Sabías que…?
SOAP empezó siendo las siglas de «Simple Object Access Protocol». Desde SOAP 1.2, el W3C ya no lo trata como unas siglas, sino como un nombre: y lo cierto es que, de «simple», le quedaba poco.
Interactivo
Siete formas de diseñar una API
Activa o desactiva opciones para compararlas cara a cara.
| Característica | REST | GraphQL | gRPC |
|---|---|---|---|
| Piensas en | Recursos con URL | Un esquema de tipos que el cliente consulta | Servicios con métodos |
| Formato | JSON, normalmente | JSON | Protocol Buffers (binario) |
| Transporte | HTTP | HTTP, casi siempre POST a /graphql | HTTP/2; en el navegador, gRPC-Web |
| Contrato | Opcional, con OpenAPI | Obligatorio: el esquema | Obligatorio: el .proto |
| Caché de HTTP | Sí, en las respuestas a GET | Difícil: se cachea en el cliente | No |
| Uso típico | APIs públicas y operaciones CRUD | Frontends con pantallas muy variadas | Microservicios internos y streaming |
Ponlo en práctica
Saber qué es cada cosa es la mitad del trabajo. La otra mitad es reconocer cuándo usarla.
Interactivo
¿Qué usarías?
Lee cada situación y elige la opción que mejor la resuelve. Fallar aquí no cuenta: es para practicar.
Vas a publicar una API de datos meteorológicos para que la use cualquiera. Quieres que funcione con curl y que un CDN pueda cachear las respuestas.
Para recordar
- REST organiza la API en recursos con URL y usa los verbos y códigos de HTTP: es simple y se cachea bien, pero una pantalla puede recibir campos de más o necesitar varias peticiones.
- GraphQL deja que el cliente pida exactamente lo que necesita en una sola consulta, a cambio de una caché HTTP más difícil y de vigilar el problema N+1 en el servidor.
- JSON:API no es un protocolo nuevo: es una convención para que las APIs REST en JSON tengan siempre la misma forma.
- XML-RPC, SOAP, JSON-RPC y gRPC piensan en funciones remotas; gRPC destaca entre servicios internos por su contrato
.proto, su binario compacto y el streaming. - SOAP y XML-RPC siguen vivos en integraciones veteranas: los usarás cuando la otra parte los exija.
Comprueba lo aprendido
Cuestionario
Responde las 5 preguntas para completar la lección.
1.El endpoint
GET /usuarios/7devuelve 30 campos y tu pantalla solo usa 2. ¿Cómo se llama este problema?2.Una consulta GraphQL pide 20 posts con su autor, y el servidor acaba haciendo 21 consultas a la base de datos. ¿Cuál es la solución habitual?
3.¿Qué significa que una API REST sea «sin estado»?
4.¿Por qué una web no puede llamar directamente a un servicio gRPC estándar desde el navegador?
5.En JSON-RPC 2.0 envías una petición sin
id. ¿Qué ocurre?