El problema
El primer paso fue revisar los logs del sistema para entender qué estaba fallando exactamente. Después de analizar, encontré que el error estaba relacionado con CSRF en una petición GraphQL al momento de enviar el archivo de imagen.
Esto indicaba que el problema no estaba necesariamente en la lógica de negocio, sino en cómo se estaba enviando y procesando el archivo dentro de la arquitectura GraphQL.
Flujo de la arquitectura
El sistema utiliza una arquitectura con:
- GraphQL Gateway: El punto de entrada del sistema.
- Subgraph: Donde vive la lógica del sistema.
Todas las peticiones pasan primero por el gateway, que se encarga de aspectos como autenticación y enrutamiento hacia los subgraphs.
Para entender mejor el problema, hice una prueba: envié la petición directamente al subgraph, saltándome el gateway y obtuve que la imagen se subió correctamente.
Esto confirmó que el problema ocurría cuando el archivo pasaba por el gateway hacia el subgraph, donde por alguna razón no se estaba transfiriendo correctamente.
Posibles soluciones
A partir de ahí comencé a investigar diferentes enfoques. Revisé documentación y probé varias configuraciones relacionadas con librerías de uploads en GraphQL.
No encontré una solución, entonces decidí evaluar distintas alternativas.
Opción 1: Enviar las peticiones directamente al subgraph
Técnicamente funcionaba, pero rompería la arquitectura del sistema, ya que el gateway debe ser el único punto de entrada. Además, implicaría riesgos de seguridad.
Opción 2: Enviar la imagen como Base64
Otra alternativa era codificar la imagen en Base64 desde el cliente y enviarla como parte de la mutación GraphQL.
Aunque esto solucionaría el problema del upload, tiene varias desventajas:
- Aumenta considerablemente el tamaño del payload.
- No es eficiente para archivos grandes.
- No escala bien en producción.
La solución adoptada
Finalmente opté por una solución más simple y común en muchas arquitecturas modernas: separar el manejo de archivos de GraphQL.
Implementé un endpoint REST en Express.js dedicado únicamente a la subida de imágenes.
El flujo quedó:
- El cliente envía la imagen al endpoint REST de subida de archivos.
- El servidor procesa y almacena la imagen.
- El endpoint devuelve la URL donde quedó guardada la imagen.
- Luego el cliente ejecuta una mutación GraphQL para actualizar el perfil del usuario con esa URL.
A veces la mejor solución no es la más compleja, sino la que respeta mejor la arquitectura del sistema y reduce los puntos de fallo.