Skip to main content

Les erreurs de resolver arrivent avec HTTP 200

C’est la chose la plus importante à savoir avant d’écrire votre gestion des erreurs. Conformément à la spécification GraphQL over HTTP, une requête qui atteint nos resolvers renvoie HTTP 200 même lorsqu’une opération a échoué. L’échec est signalé dans le corps de la réponse, et non par le code de statut. Cette vérification ne fonctionne donc pas :
Vérifiez plutôt le corps. Quelques erreurs de transport, comme 415 pour un Content-Type non pris en charge, ont un corps vide ; vérifiez donc que la réponse est au format JSON avant de l’analyser :
Certains échecs sont détectés avant toute exécution. Aucun d’eux n’atteint un resolver ni ne consomme d’appel API :
  • Une requête mal formée renvoie un statut d’erreur : HTTP 400 pour un JSON invalide ou une query manquante, 413 pour un corps de plus de 64 Ko, 405 pour une méthode autre que POST, et 415 pour un Content-Type non pris en charge.
  • Une query non valide pour le schéma renvoie HTTP 400 uniquement si votre requête envoie Accept: application/graphql-response+json. Cela couvre une erreur de syntaxe, un champ inconnu, un mauvais type d’argument, une valeur d’enum invalide et une query dépassant les limites de requête. Si vous envoyez Accept: application/json, ou aucun en-tête Accept, la même erreur renvoie HTTP 200. Dans les deux cas, le corps contient un tableau errors et pas de data.
Une fois l’exécution commencée, la validation des entrées au niveau du resolver et les échecs de l’API (y compris l’authentification, l’autorisation, les limites de débit en amont et les réponses 5xx en amont) renvoient HTTP 200 avec un tableau errors.

La structure d’une erreur

Chaque erreur de resolver transporte son statut d’API de type HTTP dans extensions :
  • message : une description lisible par un humain. Nous retirons les API Keys et autres identifiants des messages d’erreur des resolvers, mais une erreur portant sur une valeur que vous avez envoyée, comme une variable du mauvais type, peut reprendre cette valeur. Considérez message comme potentiellement sensible avant de le journaliser.
  • path : le champ de votre query qui a échoué. Avec plusieurs champs dans une requête, c’est ainsi que vous savez lequel.
  • extensions.status : le statut HTTP que l’appel REST équivalent aurait renvoyé. Basez votre logique sur cette valeur.
  • extensions.code : le code d’erreur numérique Ayrshare, lorsque le point de terminaison sous-jacent en fournit un.
  • extensions.retryAfter : présent sur les 429 de quota ou de limite de débit en amont lorsqu’un délai avant nouvelle tentative est disponible. Il n’est pas présent sur le 429 du budget de dispatch par requête.
Utilisez extensions.code avec la référence des codes d’erreur, ou transmettez-le à explainError.

Succès partiel

Si une requête demande plusieurs choses et que seules certaines réussissent, vous obtenez à la fois data et errors :
history a réussi et ses données sont utilisables. Seul analytics doit être relancé. Ne rejetez pas toute la réponse parce que errors est présent : vous jetteriez des données qui vous ont déjà été facturées.

Succès partiel sur les publications multi-réseaux

Une publication sur plusieurs réseaux peut réussir sur certains et échouer sur d’autres. Ce cas n’est pas signalé comme une erreur GraphQL, car l’opération elle-même a fonctionné : elle a fait exactement ce que vous avez demandé et vous indique ce qui s’est passé. Le résultat distingue les trois issues :
  • postIds : les réseaux sur lesquels la publication a réussi, avec les URL des publications. Uniquement les succès.
  • errors : les réseaux qui ont échoué, avec la raison.
  • blocked : les réseaux arrêtés avant toute tentative, par exemple par le disjoncteur par réseau après des échecs déterministes répétés. Ils sont distincts des tentatives auprès du fournisseur qui ont renvoyé des erreurs.
status vaut "error" si au moins un réseau a échoué ; ce n’est donc pas un signal fiable indiquant que rien n’a été publié. Lisez postIds pour savoir ce qui l’a été.

Nouvelles tentatives

L’API GraphQL ne relance jamais automatiquement. Si une requête échoue, rien n’a été retenté silencieusement en votre nom. C’est surtout important pour les mutations. createPost expose idempotencyKey : générez une clé unique avant la première tentative, puis réutilisez la même clé et un payload identique pour chaque nouvelle tentative. Une nouvelle tentative réglée rejoue le résultat d’origine au lieu de répéter l’écriture. Ne passez pas à une nouvelle clé après une réponse ambiguë. boostFacebookPost et instagramBoostPost acceptent également une idempotencyKey, et elle protège de l’argent réel. Une nouvelle tentative avec la même clé et les mêmes arguments renvoie le résultat d’origine, marqué idempotentReplayed: true, au lieu de créer et de payer une seconde publicité. Une clé couvre l’ensemble de votre compte sur les deux plateformes Meta ; ne réutilisez donc jamais la clé d’un boost Facebook pour un boost Instagram. Lorsqu’une clé est refusée, extensions.status vous indique pourquoi. createPost renvoie 409 tant que la première tentative est encore en cours de traitement ; attendez alors et réessayez avec la même clé. Il renvoie 400 lorsque le payload diffère de celui de la première tentative. Les mutations de boost renvoient 409 dans les deux cas, ainsi que lorsque la clé a été utilisée pour un boost sur l’autre plateforme. Les autres écritures, comme addComment, n’ont pas de clé d’idempotence. Si leur réponse est perdue, vérifiez l’état du réseau social ou de l’API avant de décider si une nouvelle tentative est sans risque. Deux limites différentes renvoient toutes deux 429, et elles nécessitent un traitement différent. Le budget de dispatch ne rejette des champs racine qu’une fois que cinq appels API ont déjà démarré dans la même requête, et son message commence par Query exceeds the per-request dispatch budget : répartissez ces champs dans des requêtes de cinq au maximum, sans avoir besoin d’attendre. Tout autre 429 correspond à une limite de débit ou à un quota : attendez extensions.retryAfter secondes lorsqu’il est présent, sinon espacez vos tentatives avant de réessayer, et ne relancez que les champs qui ont échoué. Pour un 5xx sur une lecture, réessayer est sans risque, à une exception près : generatePost est une query, mais une nouvelle tentative rappelle le générateur IA, compte comme un appel API supplémentaire et renvoie un texte différent. Pour un 5xx sur une écriture sans idempotence, vérifiez si elle a pris effet avant de réessayer.

Statuts courants

Les erreurs levées par GraphQL lui-même avant l’exécution, comme un champ inconnu, un mauvais type d’argument ou une valeur d’enum invalide, n’ont pas d’extensions.status. Elles renvoient HTTP 400 ou 200 selon votre en-tête Accept, comme décrit ci-dessus. Elles signifient que la query elle-même est incorrecte, et aucun appel API n’a été effectué ni facturé.