Skip to main content

Los errores del resolver llegan con HTTP 200

Esto es lo más importante que debes saber antes de escribir la gestión de errores. Siguiendo la especificación GraphQL over HTTP, una solicitud que llega a nuestros resolvers devuelve HTTP 200 incluso cuando una operación ha fallado. El fallo se informa dentro del cuerpo de la respuesta, no mediante el código de estado. Por lo tanto, esta comprobación no funciona:
Comprueba el cuerpo en su lugar. Algunos errores de transporte, como el 415 por un Content-Type no admitido, tienen el cuerpo vacío, así que comprueba que la respuesta sea JSON antes de analizarla:
Algunos fallos se detectan antes de que se ejecute nada. Ninguno de ellos llega a un resolver ni consume una llamada a la API:
  • Una solicitud mal formada devuelve un estado de error: HTTP 400 por JSON no válido o una query ausente, 413 por un cuerpo de más de 64 KB, 405 por un método distinto de POST y 415 por un Content-Type no admitido.
  • Una query que no es válida para el esquema devuelve HTTP 400 solo si tu solicitud envía Accept: application/graphql-response+json. Esto incluye un error de sintaxis, un campo desconocido, un tipo de argumento incorrecto, un valor de enum no válido y una query que supera los límites de consulta. Si envías Accept: application/json, o ningún encabezado Accept, el mismo error devuelve HTTP 200. En ambos casos, el cuerpo tiene un array errors y ningún data.
Una vez que comienza la ejecución, la validación de entrada a nivel de resolver y los fallos de la API (incluidos autenticación, autorización, rate limits del servicio subyacente y respuestas 5xx del servicio subyacente) devuelven HTTP 200 con un array errors.

La estructura del error

Cada error del resolver incluye su estado de la API, similar a HTTP, en extensions:
  • message: una descripción legible. Eliminamos las API Keys y otras credenciales de los mensajes de error del resolver, pero un error sobre un valor que enviaste, como una variable del tipo incorrecto, puede repetir ese valor. Trata message como posiblemente sensible antes de registrarlo.
  • path: qué campo de tu query falló. Con varios campos en una solicitud, así es como sabes cuál.
  • extensions.status: el estado HTTP que habría devuelto la llamada REST equivalente. Básate en este valor.
  • extensions.code: el código de error numérico de Ayrshare, cuando el endpoint subyacente proporciona uno.
  • extensions.retryAfter: presente en los 429 de cuota o rate limit del servicio subyacente cuando hay un tiempo de espera de reintento disponible. No está presente en el 429 del presupuesto de despacho por solicitud.
Usa extensions.code con la referencia de códigos de error, o pásalo a explainError.

Éxito parcial

Si una solicitud pide varias cosas y solo algunas tienen éxito, obtienes tanto data como errors:
history tuvo éxito y sus datos se pueden usar. Solo hay que reintentar analytics. No descartes toda la respuesta porque haya errors: estarías tirando datos que ya se te han facturado.

Éxito parcial en publicaciones en varias redes

Una publicación en varias redes puede tener éxito en algunas y fallar en otras. Esto no se informa como un error de GraphQL, porque la operación en sí funcionó: hizo exactamente lo que pediste y te está indicando lo que ocurrió. El resultado separa los tres desenlaces:
  • postIds: las redes en las que se publicó, con las URLs de sus publicaciones. Solo los éxitos.
  • errors: las redes que fallaron, con el motivo.
  • blocked: las redes que se detuvieron antes de intentarlo, por ejemplo por el circuit breaker por red tras fallos deterministas repetidos. Son distintas de los intentos ante el proveedor que devolvieron errores.
status es "error" si cualquier red falló, así que no es una señal fiable de que no se publicó nada. Lee postIds para saber qué se publicó.

Reintentos

La API GraphQL nunca reintenta automáticamente. Si una solicitud falla, no se ha vuelto a intentar nada en silencio en tu nombre. Esto importa sobre todo en las mutations. createPost expone idempotencyKey: genera una clave única antes del primer intento y luego reutiliza la misma clave y una carga útil idéntica en cada reintento. Un reintento ya resuelto reproduce el resultado original en lugar de repetir la escritura. No cambies a una clave nueva tras una respuesta ambigua. boostFacebookPost e instagramBoostPost también reciben un idempotencyKey, y este protege dinero real. Un reintento con la misma clave y los mismos argumentos devuelve el resultado original, marcado con idempotentReplayed: true, en lugar de crear y pagar un segundo anuncio. Una clave cubre toda tu cuenta en ambas plataformas de Meta, así que nunca reutilices la clave de una promoción de Facebook para una promoción de Instagram. Cuando se rechaza una clave, extensions.status te indica el motivo. createPost devuelve 409 mientras el primer intento aún se está procesando, así que espera y reintenta con la misma clave, y 400 cuando la carga útil difiere de la del primer intento. Las mutations de promoción devuelven 409 en ambos casos, y también cuando la clave se usó para una promoción en la otra plataforma. Otras escrituras, como addComment, no tienen clave de idempotencia. Si se pierde su respuesta, comprueba el estado de la red social o de la API antes de decidir si es seguro volver a intentarlo. Dos límites distintos informan ambos de un 429, y requieren una gestión diferente. El presupuesto de despacho solo rechaza campos raíz una vez que ya se han iniciado cinco llamadas a la API en la misma solicitud, y su mensaje empieza por Query exceeds the per-request dispatch budget: divide esos campos en solicitudes de cinco como máximo, sin necesidad de esperar. Cualquier otro 429 es un rate limit o una cuota: espera extensions.retryAfter segundos cuando esté presente; de lo contrario, aplica un backoff antes de reintentar, y reintenta solo los campos que fallaron. Ante un 5xx en una lectura, reintentar es seguro, con una excepción: generatePost es una query, pero un reintento vuelve a llamar al generador de IA, cuenta como otra llamada a la API y devuelve un texto distinto. Ante un 5xx en una escritura sin idempotencia, verifica si surtió efecto antes de reintentar.

Estados habituales

Los errores que genera el propio GraphQL antes de la ejecución, como un campo desconocido, un tipo de argumento incorrecto o un valor de enum no válido, no tienen extensions.status. Devuelven HTTP 400 o 200 según tu encabezado Accept, como se describe arriba. Significan que la propia query es incorrecta, y no se realizó ni se facturó ninguna llamada a la API.