MAISON CODE .
/ Tech · Architecture · API · GraphQL · TypeScript · Backend

La capa API moderna: GraphQL, REST y tRPC

El debate ha terminado. Necesitas seguridad de tipos. Cómo diseñar una capa API escalable que no rompa el frontend cuando el backend estornuda.

AB
Alex B.
La capa API moderna: GraphQL, REST y tRPC

Por qué Maison Code habla de esto

En Maison Code Paris, actuamos como la conciencia arquitectónica de nuestros clientes. A menudo heredamos stacks “modernos” construidos sin una comprensión fundamental de la escala.

Discutimos este tema porque representa un punto de inflexión crítico en la madurez de la ingeniería. Implementarlo correctamente diferencia un MVP frágil de una plataforma resistente de nivel empresarial.

El problema “Indefinido no es una función”

Durante 20 años, los desarrolladores frontend y backend vivieron en silos. Backend Dev: “Actualicé la API de usuario. Devuelve fullName en lugar de first_name”. Desarrollador de interfaz: “Está bien”. (Se olvida de actualizar el código). Producción: Accidente. usuario.primer_nombre no está definido. Esto se llama Brecha de Integración. La documentación (Swagger/OpenAPI) ayuda, pero la documentación miente. Se vuelve obsoleto. La solución moderna es Seguridad de tipo de extremo a extremo. El código en sí previene estos errores de discrepancia.

Por qué Maison Code analiza la arquitectura API

En Maison Code, heredamos proyectos donde la capa API es un desastre de puntos finales espagueti. /api/v1/get-user-final-final-2. Esto ralentiza la velocidad de la característica a un ritmo lento. Implementamos Arquitecturas de tipo seguro. Habilitamos Autonomía Frontend. El equipo de frontend no debería tener que molestar al equipo de backend para que agregue un campo a una respuesta JSON. Escribimos sobre esto porque los equipos escalables funcionan con contratos escalables. Si su esquema está flojo, su producto está flojo.

1. Los contendientes

1. DESCANSO (con OpenAPI)

El clásico.

  • Pros: Simple, almacenable en caché (HTTP 200), universal.
  • Contras: recuperación excesiva (obtener demasiados datos) y recuperación insuficiente (n+1 solicitudes).
  • Giro moderno: use OpenAPI (Swagger) para generar tipos de TypeScript automáticamente. npx openapi-typescript esquema.json -o esquema.d.ts. Ahora, si el backend cambia, la compilación del frontend falla.

2. GraphQL

El usuario avanzado.

  • Pros: El cliente pide exactamente lo que necesita.
    consulta {usuario {nombre, avatar(tamaño: PEQUEÑO) } }
  • Contras: Almacenamiento en caché complejo (todo es POST 200), complejidad (Resolvedores, Cargadores de datos).
  • Mejor para: aplicaciones complejas con muchos gráficos (redes sociales, paneles) e integraciones de CMS sin cabeza (Shopify, Contentful).

3. tRPC (Llamada a procedimiento remoto de TypeScript)

El demonio de la velocidad.

  • Contexto: si posee tanto el frontend como el backend (por ejemplo, Next.js Monorepo).
  • Magic: Importas la función backend directamente al código frontend.
    // servidor
    exportar const appRouter = enrutador({
      getUser: publicProcedure.query(() => { id: 1, nombre: 'Alex' })
    });
    
    // interfaz
    usuario constante = trpc.getUser.useQuery();
    console.log(nombre.datos.usuario); // ¡Escrito!
  • No existe un esquema API. El código es el esquema.
  • Contras: Bloqueado en monorepos de TypeScript.

2. Patrón: The BFF (Backend para Frontend)

En las arquitecturas de microservicio, no desea que la interfaz llame a 10 servicios distintos (servicio de usuario, servicio de carrito, servicio de producto). Es lento (10 viajes de ida y vuelta) y complicado. Solución: una capa BFF (normalmente rutas API GraphQL o Next.js). El Frontend llama al BFF una vez. El BFF llama a los 10 servicios, agrega los datos, elimina secretos y devuelve un JSON limpio. Esto permite que el Frontend sea “tonto” y el Backend sea “complejo” sin perjudicar el rendimiento.

3. Validando las Entradas: Zod

Nunca confíes en el cliente. Ya sea que use REST o GraphQL, debe validar las entradas. Zod es el estándar.

importar {z} desde 'zod';

const UserSchema = z.objeto({
  correo electrónico: z.string().email(),
  edad: z.número().min(18)
});

aplicación.post('/usuario', (req, res) => {
  resultado constante = UserSchema.safeParse(req.body);
  si (!resultado.éxito) {
    devolver res.status(400).json(result.error);
  }
  // Es seguro continuar
});

Este esquema de Zod se puede compartir con la interfaz para generar la lógica de validación de formulario automáticamente (usando react-hook-form).

4. La capa de Federación (Apolo)

Para aplicaciones empresariales, un servidor GraphQL no es suficiente. Tienes el “Equipo de Producto” en Berlín y el “Equipo de Pago” en Nueva York. No pueden compartir una base de código. Solución: Federación GraphQL. Cada equipo construye su propio Subgraph. Una “Puerta de enlace” los une en un “Supergrafo”. El Frontend consulta el Gateway. Parece una API, pero funciona con 50 microservicios. Esta es la arquitectura de Netflix y Airbnb.

5. Estrategias de manejo de errores

“200 OK” pero errores: ["No encontrado"]. Esta es la trampa de GraphQL. Estrategia:

  1. Errores de red: (DNS, 500s). Vuelva a intentarlo con retroceso exponencial.
  2. Errores de Lógica: (Usuario no encontrado). Devuelve un tipo que acepta valores NULL o un tipo de unión.
    union ResultadoUsuario = Usuario | Usuario no encontrado | Permiso denegado
    Esto obliga a la interfaz a manejar el caso de error explícitamente en el código. si (resultado.__typename === 'UserNotFound') ... Manejo de errores de tipo seguro.

6. Estrategias de almacenamiento en caché (obsoletas mientras se revalidan)

REST almacena en caché fácilmente a través de encabezados HTTP (Cache-Control: max-age=3600). GraphQL es más difícil. Usamos Stale-While-Revalidate (SWR) en el cliente (TanStack Query).

  1. Muestra los datos almacenados en caché al instante (obsoletos).
  2. Obtenga nuevos datos en segundo plano (Revalidar).
  3. Actualice la interfaz de usuario si se modifica. Esto hace que la aplicación parezca “instantánea”, incluso si la red es lenta.

7. La capa de seguridad (limitación de velocidad y JWT)

Una API sin seguridad es una puerta abierta. Limitación de velocidad: evita ataques DDoS.

  • Utilice upstash/ratelimit (Redis) en Edge.
  • “10 solicitudes cada 10 segundos por IP”. Autenticación:
  • Dejar de utilizar cookies para API. Utilice JWT (tokens web JSON) en el encabezado “Autorización: Portador”.
  • Apátrida. Escalable.
  • Pero asegúrese de manejar la rotación de tokens (actualizar tokens) de forma segura. Validación:
  • Sanitizar entradas contra Inyección SQL (usar ORMs).
  • Sanitizar las salidas contra XSS.

8. Integración de migración heredada (La figura estranguladora)

Tienes una API heredada monolítica (Java/PHP). Quieres una API Node.js moderna. No lo reescribas todo de una vez. Fallarás. Utilice el Patrón de higo estrangulador.

  1. Pon un Proxy (Nginx/Cloudflare) al frente.
  2. Enrute /api/v1/users a la Nueva API.
  3. Enrute todo lo demás a la API heredada.
  4. Migre lentamente los puntos finales uno por uno.
  5. Apague la API heredada cuando el tráfico baje a cero. Esto le permite enviar valor inmediatamente sin una reescritura tipo “Big Bang”.

9. Documentos como código (estándar Stripe)

¿Cómo hace Stripe para que sus documentos sean tan buenos? Los generan a partir del código. No escriba documentos API en Word o Confluence. Escríbalos en el Esquema.

  • OpenAPI: agregue campos de descripción a su YAML.
  • GraphQL: agregue """ cadenas de documentación """ a su esquema.
  • Herramientas: utilice Scalar o Redoc para representar hermosos documentos HTML a partir del esquema.
  • CI/CD: implemente documentos automáticamente en cada combinación. Los documentos obsoletos son peores que no tenerlos.

10. La visión del escéptico

“GraphQL está muerto. Solo usa fetch”. Contrapunto: GraphQL está vivo y coleando en la empresa. Shopify, GitHub y Facebook se ejecutan en él. “Simplemente buscar” funciona para blogs. No funciona para una página de producto de comercio electrónico que necesita precio, variantes, inventario, reseñas, recomendaciones y estado de lista de deseos del usuario en una sola solicitud. Si hace eso con REST, tendrá 6 solicitudes (lentas) o un punto final monstruoso /get-product-page-data (no mantenible). GraphQL resuelve el problema de Orquestación.

11. Tráfico interno: Búfers de protocolo (gRPC)

JSON es legible por humanos. También es lento. Repite claves: {"nombre": "alex", "edad": 10}. “nombre” se envía por cable cada vez. gRPC usa Protobuf (binario). Envía 0x12 0x04 0x61 0x6c 0x65 0x78. Es un 30% más pequeño y 5 veces más rápido de analizar. Usamos gRPC para la comunicación interna de servicio a servicio (Microservicios). Usamos GraphQL/JSON para la comunicación Cliente-Servidor. Herramienta adecuada para el trabajo adecuado.

12. El problema N+1 (cargadores de datos)

El clásico asesino de GraphQL. Consulta: usuarios {publicaciones {título}}.

  • 1 Consulta para Usuarios (SELECCIONAR * DE usuarios).
  • 100 consultas para publicaciones (SELECCIONAR * DE publicaciones DONDE user_id = 1… 100).
  • Total: 101 llamadas a BD. Solución: Cargador de datos. Agrupa las 100 solicitudes en UNO. SELECCIONAR * DE publicaciones DONDE user_id EN (1, 2, ... 100). Esto reduce la carga de la base de datos en un 99%. Si no utiliza DataLoaders, su servidor GraphQL se derretirá.

13. Conclusión

La capa API es el sistema nervioso de su aplicación. Si es débil (no tipificado, no probado), el cuerpo falla. Si es fuerte (tRPC, GraphQL Federation), el cuerpo se mueve con agilidad. Deja de adivinar correctamente los nombres. Empiece a hacerlas cumplir. Contrato primero. Código Segundo.


¿API rompe el frontend?

Diseñamos capas de API Type-Safe utilizando GraphQL y tRPC para garantizar cero errores de integración.

Reparar mi API. Contrate a nuestros arquitectos.