API REST vs GraphQL vs gRPC: guía de diseño 2026
En pocas palabras: REST domina con el 80% de las APIs públicas, GraphQL (desde 2015) da control al cliente y gRPC (v1.0 en 2016) usa Protobuf para microservicios. Versioná en la URL o headers, asegurá idempotencia con PUT/DELETE y comunicá errores con códigos HTTP 4xx/5xx.
Diseñar una API es mucho más que elegir un protocolo. Es firmar un contrato que queda congelado apenas el primer cliente externo lo integra. Elegir entre REST, GraphQL o gRPC define cómo modelás recursos, cómo versionás, cómo manejás la idempotencia y cómo comunicás errores. Cada estilo tiene su lugar, y pifiarle desde el arranque te puede salir caro en tiempo y reputación.
Una API (Application Programming Interface) es un contrato que define cómo dos sistemas se comunican entre sí. REST, GraphQL y gRPC son los tres estilos dominantes para diseñar APIs: REST organiza recursos con URLs y métodos HTTP, GraphQL permite que el cliente decida exactamente qué datos quiere, y gRPC usa Protocol Buffers para lograr comunicación binaria de alta velocidad, pensada sobre todo para microservicios. La elección impacta directamente en cómo versionás, cómo asegurás que una operación repetida no cause desastres (idempotencia) y cómo le contás a un cliente si el problema fue de su lado o del tuyo.
En 30 segundos
- REST es el estándar para APIs públicas por su simplicidad y el cacheo HTTP que trae de fábrica, pero sufre de over-fetching y under-fetching si el cliente necesita datos muy específicos.
- GraphQL te deja pedir exactamente lo que necesitás en una sola consulta, ideal para frontends complejos con múltiples fuentes de datos; el costo es mayor complejidad en el servidor y en el manejo de caché.
- gRPC es imbatible en velocidad para comunicación interna entre microservicios gracias a HTTP/2 y protobuf, pero no funciona en browsers sin un proxy gRPC-web, así que no es opción para APIs públicas.
- La idempotencia no es opcional cuando hay plata de por medio. Métodos como GET, PUT y DELETE son naturalmente idempotentes; para POST usá idempotency keys.
- El versionado con headers (Accept-Version) es más limpio que meter
/v1en la URL, y te permite evolucionar el contrato sin romper a los clientes que no quieren actualizarse.
¿Por qué el diseño de API se considera un contrato congelado?
Porque una vez que un cliente externo integra contra tu API, cada campo, código de estado y endpoint queda fijo por años. Modificar algo puede romper integraciones que nadie mantiene hace meses. A diferencia de una base de datos o un servicio interno —que migrás a tu propio ritmo—, la superficie pública de una API es una promesa que le hiciste a terceros a nombre de tu yo futuro. Según el análisis de Roni Das en Dev.to, “a public API surface is a promise you signed on behalf of your future self”.
Ponele que diseñás un endpoint de usuarios y decidís que el campo name incluya nombre y apellido juntos. Tres años después, un cliente nuevo te pide separarlos. Si lo cambiás, rompés a todos los que ya parseaban ese campo. Si lo mantenés, arrastrás deuda técnica para siempre. Ahora bien, ¿es evitable? En parte sí, pero requiere pensar en el diseño como si fuera a permanecer intacto por una década.
El problema no es solo la data sino el comportamiento: qué devuelve un POST, cuándo un 404 es un error o “no encontrado”, cómo paginás. Cada decisión que tomás en el día uno se convierte en dependencia de producción para otros equipos. Y esos equipos, cuando algo funciona, no vuelven a tocar el código —hasta que tu cambio lo revienta.
¿Cuándo usar REST, GraphQL o gRPC? Diferencias principales y casos de uso
REST es el enfoque más maduro y el que mejor aprovecha la infraestructura HTTP: caché, balanceadores, proxies. Organizás recursos con URLs y usás verbos (GET, POST, PUT, DELETE). Es simple, predecible y la mayoría de las APIs públicas (GitHub, Stripe, Twilio) lo usan. El punto flojo es que el cliente recibe lo que el servidor decidió darle: ni más ni menos. Eso genera over-fetching cuando el response incluye campos que no necesitás, y under-fetching cuando tenés que hacer múltiples requests para armar una vista.
GraphQL invierte el control: el cliente especifica exactamente los campos que quiere en cada consulta. Es un golazo para frontends complejos que consumen datos de múltiples fuentes, porque resolvés todo en un solo round-trip. El lado B es que el servidor ahora tiene que resolver consultas arbitrarias, lo que puede volverse un bardo de performance sin un buen sistema de caché y análisis de complejidad.
gRPC es la bestia de alto rendimiento. Usa HTTP/2, multiplexa streams, serializa con Protocol Buffers (binario, mucho más compacto que JSON) y tiene soporte nativo para streaming bidireccional. Es el favorito para comunicación entre microservicios, especialmente en stacks de Kubernetes. La contra: los browsers no lo hablan directamente —necesitás gRPC-web o un proxy—, así que para APIs públicas es un dolor de cabeza. Google lo usa masivamente en sus sistemas internos. En tu flujo de integración continua profundizamos sobre esto.
Tabla comparativa: REST vs GraphQL vs gRPC
| Característica | REST | GraphQL | gRPC |
|---|---|---|---|
| Formato de datos | JSON, XML, HTML | JSON | Protocol Buffers (binario) |
| Transporte | HTTP 1.1/2 | HTTP 1.1/2 | HTTP/2 obligatorio |
| Flexibilidad de consultas | Baja (respuestas fijas) | Muy alta (cliente elige) | Alta (definida por .proto) |
| Cacheo HTTP nativo | Sí, excelente | Complicado (POST mayormente) | No (binario) |
| Rendimiento | Medio | Medio (depende de la query) | Muy alto |
| Uso en browsers | Directo | Directo | Requiere gRPC-web |
| Curva de aprendizaje | Baja | Media | Alta |

¿Cómo manejar el versionado en una API sin romper clientes?
La regla de oro es: nunca rompas un contrato que ya publicaste. El versionado te permite evolucionar la API ofreciendo cambios incompatibles bajo una nueva versión, mientras la anterior sigue funcionando para los clientes que no migraron.
Tenés tres estrategias clásicas. La primera es versionado por URL (/api/v2/users), que es la más visible pero ensucia la ruta y duplica recursos. La segunda es versionado por header (Accept-Version: v2 o API-Version: 2026-07-20), más elegante porque mantiene una sola URL canónica y delega la negociación al header. La tercera es versionado por parámetro de query (/users?version=2), que zafa pero es la menos RESTful de todas.
Yo me inclino por headers, sobre todo si usás algo como Accept-Version con un formato de fecha. Mantenés las URLs limpias, podés agregar deprecation warnings en los headers de respuesta, y el cliente que no manda el header recibe la versión default. Eso sí: documentalo bien, porque no es obvio a simple vista como una URL.
GraphQL encara el versionado distinto: evita los breaking changes por diseño. En vez de versionar, recomendás evolución continua: agregás campos nuevos sin quitar los viejos, y deprecás campos con el decorator @deprecated. Si realmente necesitás cortar algo, lo hacés en un nuevo endpoint o con un nuevo schema, pero es raro.
gRPC maneja el versionado a nivel de definición en los archivos .proto. Cada servicio y método tiene un número de versión en el package name (por ejemplo, package myapp.v2). Como gRPC se usa sobre todo en entornos internos donde controlás ambos extremos, podés darte el lujo de coordinar actualizaciones sin tanto drama. Pero el principio es el mismo: el contrato viejo sigue funcionando hasta que el último cliente se actualiza.
¿Qué es la idempotencia y cómo implementarla en APIs REST, GraphQL y gRPC?
Una operación es idempotente si ejecutarla una vez o cien veces produce el mismo resultado y no genera efectos secundarios duplicados. En APIs, esto es crítico cuando hay plata, envío de formularios o cualquier mutación que no querés que ocurra dos veces porque el cliente retransmitió por un timeout.
En REST, los métodos GET, PUT y DELETE son idempotentes por especificación HTTP. GET no modifica nada. PUT reemplaza el recurso por completo: si lo mandás dos veces, el recurso queda en el mismo estado. DELETE borra el recurso: la segunda llamada devuelve 404, pero el estado final es el mismo. POST no es idempotente —y es justamente el que más se usa para crear recursos. Cada POST puede crear un nuevo recurso, por eso necesitás un mecanismo extra. Esto se conecta con lo que analizamos en elegir entre Jenkins y GitHub Actions.
La solución estándar es la idempotency key: un identificador único que el cliente genera y manda en un header (Idempotency-Key). El servidor lo almacena junto con el resultado de la primera operación; si recibe el mismo key de nuevo, devuelve el resultado original sin re-ejecutar la mutación. Esta técnica es hoy moneda corriente. Implementarlo en tu API REST te saca el problema de raíz: el cliente reintenta tranquilo, el servidor no cobra dos veces.
En GraphQL, las mutaciones no son automágicamente idempotentes. Depende de cómo las diseñes. Podés agregar un argumento idempotencyKey en tus mutaciones y manejarlo del lado del resolver. La comunidad no tiene un estándar único, así que vas a tener que definir vos la convención.
En gRPC, el soporte de idempotencia es más explícito: desde hace un tiempo, podés marcar métodos como idempotentes en la definición .proto con option idempotency_level = IDEMPOTENT;. Pero eso es una pista, no magia —el servidor sigue siendo responsable de implementarla. Si tu método genera un pago, necesitás el mismo mecanismo de key deduplication.
¿Cómo diseñar un formato de errores que el cliente realmente entienda?
Un error HTTP pelado (un 400 sin cuerpo, por ejemplo) es inútil. El cliente necesita saber qué salió mal, a qué campo corresponde y cómo solucionarlo. La diferencia entre un API que la gente ama y una que odia está, en buena parte, en cómo comunicás los problemas.
Distinguí tres categorías con los códigos HTTP: 4xx para errores del cliente (bad input, falta de permisos, recurso no encontrado) y 5xx para fallos del servidor (base de datos caída, timeout interno). Pero el código solo no alcanza. Siempre devolvé un cuerpo estructurado que incluya un error_code (string legible por máquina), un message (legible por humano) y, opcionalmente, un array details con información por campo cuando el error es de validación.
Un formato estructurado y re piola para errores incluye campos como type, title, status, detail e instance. No es obligatorio, pero usarlo te da consistencia y evita que cada endpoint invente su propia forma de error. GraphQL, en cambio, siempre devuelve 200 OK incluso ante errores: la respuesta incluye un objeto errors con mensaje, ubicación y path. Es un approach distinto que desacopla el error del transporte.
gRPC tiene su propio sistema de códigos de error (OK, InvalidArgument, NotFound, Internal, etc.) y detalles enriquecidos vía el mensaje de status. La ventaja es que el cliente gRPC ya sabe parsearlo sin convenciones custom. Lo explicamos a fondo en optimizar tu SEO internacional.
Un ejemplo concreto: si tu API de registro recibe un email inválido, no devuelvas un 400 genérico. Devolvé un 422 Unprocessable Entity con un body como { "error": "validation_error", "message": "El email no es válido", "details": [ { "field": "email", "issue": "formato_invalido" } ] }. El frontend puede mapear eso directo al campo del formulario. Es un detalle que parece chiquito, pero te ahorra horas de debugging.
Paginación, rate limiting y otros cross-cutting concerns
Hay temas que atraviesan cualquier estilo de API y que, si no los diseñás desde el día uno, te explotan en la cara cuando el tráfico crece. La paginación es el más obvio: no podés devolver 100.000 registros en una sola response. Tenés dos sabores: paginación por offset (?page=3&per_page=50), que es simple pero inconsistente si se insertan o borran filas entre requests; y paginación por cursor (?cursor=abc123), más estable y eficiente para datasets que cambian rápido. GraphQL tiene su propio estándar de cursor-based pagination (Relay Connections), mientras que REST y gRPC lo implementan a mano.
El rate limiting es otro infaltable. Sin límites, un cliente mal configurado —o un scraper— te satura el backend. Respondé con headers como X-RateLimit-Limit, X-RateLimit-Remaining y Retry-After para que el cliente pueda autorregularse. Y si vas a poner una API pública en producción, necesitás un API gateway que haga el enforcement (Kong, Tyk, APIM de Azure, o NGINX con reglas custom).
La autenticación también es transversal. JWT, OAuth2, API keys. Definí una sola estrategia para todo el API surface y no improvises por endpoint. Si estás hosteando tu API en un VPS o servidor propio, elegir un buen proveedor de infraestructura te da la flexibilidad para configurar estos gateways sin restricciones —donweb.com tiene opciones sólidas para montar APIs en producción sin vueltas—.
Errores comunes en el diseño de APIs (y cómo evitarlos)
1. Usar POST para todo. Hay equipos que, por comodidad, mandan todas las operaciones como POST con un campo action en el body. Eso mata las ventajas de HTTP: no hay caché, no hay idempotencia clara, no hay semántica. Usá los verbos como corresponden: GET para leer, POST para crear, PUT/PATCH para actualizar, DELETE para borrar.
2. Meter información sensible en URLs. Si ponés un token de acceso en la query string (/users?api_key=sk_live_xxx), ese token queda registrado en logs de servidores, proxies, browsers y servicios de analytics. Va en headers, siempre. Preferentemente en Authorization: Bearer <token>.
3. No definir un schema de respuesta estable. Cambiar los nombres de campos sin aviso, o devolver tipos inconsistentes (a veces string, a veces número) según el estado del recurso. Para REST, usá OpenAPI y validá las responses en tests. Para GraphQL, el schema es el contrato, así que mantenelo estricto. Para gRPC, el .proto te obliga, pero igual podés meter campos opcionales de más y confundir al cliente.
4. Ignorar la idempotencia en endpoints de pago. Este es el que más duele en producción. Si tu endpoint de cobro no soporta idempotency keys, un retry por timeout puede cobrar dos veces al usuario. Implementalo desde el día uno, incluso si creés que “esto no va a fallar”. Va a fallar. Te puede servir nuestra cobertura de ejecutar agentes sin depender de APIs.
Preguntas Frecuentes
¿Cuál es la diferencia entre REST, GraphQL y gRPC?
REST expone recursos con URLs y métodos HTTP, usa JSON y aprovecha el cacheo nativo; GraphQL permite que el cliente defina la forma exacta de la respuesta mediante queries, reduciendo over-fetching; gRPC usa Protocol Buffers y HTTP/2 para lograr comunicación binaria de baja latencia, ideal para microservicios pero no apto para browsers sin proxy.
¿Qué protocolo es más rápido: gRPC o REST?
gRPC es consistentemente más rápido que REST, especialmente en comunicación interna. La serialización binaria con Protocol Buffers es más compacta que JSON, y HTTP/2 permite multiplexar streams, reducir latencia y enviar datos en ambos sentidos simultáneamente. En benchmarks típicos, gRPC puede ser entre 3 y 10 veces más rápido que REST para payloads grandes.
¿Cómo versionar una API GraphQL sin romper clientes?
GraphQL promueve la evolución continua en lugar del versionado tradicional. Agregás campos nuevos sin quitar los existentes y marcás los obsoletos con @deprecated. Si necesitás un cambio incompatible realmente grande, publicás un nuevo schema bajo un endpoint distinto, pero es una práctica poco frecuente.
¿Qué significa idempotencia en una API REST?
Significa que ejecutar la misma solicitud varias veces produce el mismo efecto que hacerlo una sola vez. Los métodos GET, PUT y DELETE son idempotentes por diseño HTTP; POST no lo es. Para mutaciones POST, se recomienda implementar idempotency keys para evitar duplicados en escenarios de reintentos.
¿Qué formato de errores conviene usar para una API REST?
Lo más recomendado es devolver un objeto JSON estructurado con campos como type, title, status, detail e instance. Siempre acompañá el código HTTP (4xx o 5xx) con un cuerpo estructurado que permita al cliente entender el problema sin tener que parsear cadenas de texto arbitrarias.
Conclusión
La decisión entre REST, GraphQL y gRPC no es religiosa: es de contexto. Si tu API es pública y la van a consumir equipos que no controlás, REST sigue siendo la opción más segura, con ecosistema maduro y cacheo que te salva el presupuesto de infra. Si tu frontend necesita consultas flexibles y sufrís over-fetching, GraphQL te ordena el quilombo, pero asumí el costo en complejidad de servidor. Si lo tuyo es pura comunicación entre microservicios con requisitos de latencia bajísima, gRPC es la respuesta y no hay discusión.
Lo que no cambia con el estilo es la disciplina: versioná sin romper, hacé que tus mutaciones de plata sean idempotentes sí o sí, y dale a tus clientes errores que realmente les sirvan para corregir el problema. Un día te toca ser el cliente de tu propia API, y cuando eso pase, vas a agradecer haberte tomado el diseño en serio.






