GraphQL vs REST: un duelo que debiste empezar ayer
\n\n¿Te suena esta situación? Estás escribiendo un nuevo proyecto en JavaScript (o Node.js) y de repente surge la pregunta: ¿qué usar para la comunicación entre el frontend y el backend? ¿El clásico REST o el moderno GraphQL? Los debates sobre este tema no cesan, y cada desarrollador tiene su opinión "de hierro".
\n\nSeamos honestos: REST es ese viejo y buen amigo que nunca te falla. GraphQL es el novato audaz que promete resolver todos tus problemas. Pero, ¿cómo elegir? No te mostraré tablas de comparación aburridas, sino ejemplos reales de combate en JavaScript. Verás cómo se ve el código, dónde surgen los obstáculos y, lo más importante, cuándo usar cada uno.
\n\nPor cierto, si desarrollas en Python (y este sitio es sobre Python, no lo olvides), los principios para elegir entre estas tecnologías son muy similares. Pero hoy hablamos de JavaScript, el lenguaje que reina tanto en el cliente como en el servidor.
\n\nMini curso intensivo: REST y GraphQL en 60 segundos
\n\nREST (Representational State Transfer)
\nEs un estilo arquitectónico donde cada recurso (usuario, publicación, comentario) tiene su propia URL. Haces una solicitud GET a /api/users/1 y obtienes el usuario. ¿Quieres sus publicaciones? Ve a /api/users/1/posts. Todo es simple, predecible, pero... a veces demasiado verboso.
GraphQL
\nEs un lenguaje de consultas y un entorno de ejecución. Tienes un único endpoint (generalmente /graphql) y tú decides qué datos quieres obtener. Sin over-fetching (cuando llegan 50 campos y solo necesitas 3) ni under-fetching (cuando necesitas hacer 5 solicitudes para armar una página).
Comparación en combate: escribiendo código en JavaScript
\n\nImaginemos una tarea típica: mostrar en la página el perfil de un usuario con sus últimas tres publicaciones. Comparemos ambos enfoques.
\n\nEjemplo de API REST en Express (Node.js)
\n\n// Servidor REST en Express\nconst express = require('express');\nconst app = express();\n\napp.get('/api/users/:id', (req, res) => {\n // Devuelve TODOS los datos del usuario\n const user = users.find(u => u.id === req.params.id);\n res.json(user); // { id, name, email, phone, address, ... }\n});\n\napp.get('/api/users/:id/posts', (req, res) => {\n // Devuelve TODAS las publicaciones del usuario\n const posts = posts.filter(p => p.userId === req.params.id);\n res.json(posts); // [{ id, title, body, createdAt, ... }]\n});\n\n// Código del cliente (frontend con fetch)\nasync function loadProfile(userId) {\n // Primera solicitud: obtenemos el usuario (llega mucha información innecesaria)\n const userResponse = await fetch(`/api/users/${userId}`);\n const user = await userResponse.json();\n \n // Segunda solicitud: obtenemos las publicaciones (de nuevo datos innecesarios)\n const postsResponse = await fetch(`/api/users/${userId}/posts`);\n const allPosts = await postsResponse.json();\n \n // Tomamos solo las 3 últimas publicaciones\n const latestPosts = allPosts.slice(0, 3);\n \n return { user, posts: latestPosts };\n}\n\nEl problema es evidente: obtuvimos muchos datos innecesarios (over-fetching). ¿Para qué necesitamos email, phone, address si solo mostramos el nombre y el avatar? Y puede haber 100 publicaciones, pero solo necesitamos 3.
\n\nEjemplo de GraphQL en Apollo Server (Node.js)
\n\n// Esquema GraphQL\nconst typeDefs = `\n type User {\n id: ID!\n name: String\n avatar: String\n posts(limit: Int): [Post]\n }\n\n type Post {\n id: ID!\n title: String\n body: String\n }\n\n type Query {\n user(id: ID!): User\n }\n`;\n\n// Resolvers (lógica de obtención de datos)\nconst resolvers = {\n Query: {\n user: (parent, { id }) => users.find(u => u.id === id),\n },\n User: {\n posts: (parent, { limit }) => {\n let result = posts.filter(p => p.userId === parent.id);\n if (limit) result = result.slice(0, limit);\n