Comprendre les erreurs d'API

Ce guide explique comment l'API Data Manager gère et communique les erreurs. Il est essentiel de comprendre la structure et la signification des erreurs d'API pour créer des applications robustes capables de gérer les problèmes de manière fluide, qu'il s'agisse d'entrées non valides ou d'une indisponibilité temporaire du service.

L'API Data Manager suit le modèle d'erreur standard des API Google, qui est basé sur les codes d'état gRPC. Chaque réponse d'API qui génère une erreur inclut un objet Status avec les éléments suivants :

  • Code d'erreur numérique.
  • Message d'erreur.
  • Informations supplémentaires facultatives sur l'erreur.

Codes d'erreur canoniques

L'API Data Manager utilise un ensemble de codes d'erreur canoniques définis par gRPC et HTTP. Ces codes fournissent une indication générale du type d'erreur. Vous devez toujours vérifier ce code en premier pour comprendre la nature fondamentale du problème.

Pour en savoir plus sur ces codes, consultez le Guide de conception d'API – Codes d'erreur.

Gérer les erreurs

Procédez comme suit en cas d'échec d'une demande :

  1. Consultez le code d'erreur pour identifier le type d'erreur.

    • Si vous utilisez gRPC, le code d'erreur se trouve dans le champ code de Status. Si vous utilisez une bibliothèque cliente, elle peut générer un type d'exception spécifique correspondant au code d'erreur. Par exemple, la bibliothèque cliente pour Java génère une exception com.google.api.gax.rpc.InvalidArgumentException si le code d'erreur est INVALID_ARGUMENT.
    • Si vous utilisez REST, le code d'erreur se trouve dans la réponse d'erreur à error.status et l'état HTTP correspondant se trouve à error.code.
  2. Recherchez la charge utile standard des détails pour le code d'erreur. Les charges utiles d'informations standards sont un ensemble de messages d'erreur provenant des API Google. Ils fournissent des informations sur les erreurs de manière structurée et cohérente. Chaque erreur de l'API Data Manager peut comporter plusieurs messages de charge utile de détails standards. Les bibliothèques clientes de l'API Data Manager comportent des méthodes d'assistance permettant d'obtenir les charges utiles de détails standards à partir d'une erreur.

    Quel que soit le code d'erreur, nous vous recommandons de vérifier et d'enregistrer les charges utiles ErrorInfo, RequestInfo, Help et LocalizedMessage.

    • ErrorInfo contient des informations qui ne figurent peut-être pas dans d'autres charges utiles.
    • RequestInfo contient l'ID de la demande, ce qui est utile si vous devez contacter l'assistance.
    • Help et LocalizedMessage contiennent des liens et d'autres informations pour vous aider à résoudre l'erreur.

    De plus, les charges utiles BadRequest, QuotaFailure et RetryInfo sont utiles pour certains codes d'erreur :

    • Si le code d'état est INVALID_ARGUMENT, vérifiez la charge utile BadRequest pour savoir quels champs ont provoqué l'erreur.
    • Si le code d'état est RESOURCE_EXHAUSTED, vérifiez les charges utiles QuotaFailure et RetryInfo pour obtenir des informations sur le quota et une recommandation concernant le délai avant nouvelle tentative.

Charges utiles de détails standards

Voici les charges utiles de détails standards les plus courantes pour l'API Data Manager :

BadRequest

Recherchez la charge utile BadRequest lorsqu'une requête échoue avec INVALID_ARGUMENT (code d'état HTTP 400).

Un message BadRequest indique que la requête comportait des champs avec des valeurs incorrectes ou qu'une valeur manquait pour un champ obligatoire. Consultez la liste field_violations dans BadRequest pour identifier les champs comportant des erreurs. Chaque entrée field_violations contient des informations pour vous aider à corriger l'erreur :

field

Emplacement du champ dans la requête, à l'aide d'une syntaxe de chemin d'accès en camel case.

Si un chemin d'accès pointe vers un élément d'une liste (champ repeated), son index est indiqué entre crochets ([...]) après le nom de la liste.

Par exemple, destinations[0].operating_account.account_id est le account_id dans le operating_account du premier élément de la liste destinations.

description

Explication de la raison pour laquelle la valeur a généré une erreur.

reason

Énumération ErrorReason, telle que INVALID_HEX_ENCODING ou INVALID_CURRENCY_CODE.

Exemples de BadRequest

Voici un exemple de réponse pour une erreur INVALID_ARGUMENT avec un message BadRequest. Le field_violations indique que l'erreur est un accountId qui n'est pas un nombre. La valeur destinations[0].login_account.account_id de field indique que accountId avec un non-respect des règles concernant les champs se trouve dans login_account du premier élément de la liste destinations.

{
  "error": {
    "code": 400,
    "message": "There was a problem with the request.",
    "status": "INVALID_ARGUMENT",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "INVALID_ARGUMENT",
        "domain": "datamanager.googleapis.com",
        "metadata": {
          "requestId": "t-a8896317-069f-4198-afed-182a3872a660"
        }
      },
      {
        "@type": "type.googleapis.com/google.rpc.RequestInfo",
        "requestId": "t-a8896317-069f-4198-afed-182a3872a660"
      },
      {
        "@type": "type.googleapis.com/google.rpc.BadRequest",
        "fieldViolations": [
          {
            "field": "destinations[0].login_account.account_id",
            "description": "String is not a valid number.",
            "reason": "INVALID_NUMBER_FORMAT"
          }
        ]
      }
    ]
  }
}

Voici un autre exemple de réponse d'erreur INVALID_ARGUMENT avec un message BadRequest. Dans ce cas, la liste field_violations affiche deux erreurs :

  1. Le premier event a une valeur qui n'est pas encodée en hexadécimal sur le deuxième identifiant utilisateur de l'événement.

  2. Le deuxième event a une valeur qui n'est pas encodée en hexadécimal sur le troisième identifiant utilisateur de l'événement.

{
  "error": {
    "code": 400,
    "message": "There was a problem with the request.",
    "status": "INVALID_ARGUMENT",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "INVALID_ARGUMENT",
        "domain": "datamanager.googleapis.com",
        "metadata": {
          "requestId": "t-6bc8fb83-d648-4942-9c49-2604276638d8"
        }
      },
      {
        "@type": "type.googleapis.com/google.rpc.RequestInfo",
        "requestId": "t-6bc8fb83-d648-4942-9c49-2604276638d8"
      },
      {
        "@type": "type.googleapis.com/google.rpc.BadRequest",
        "fieldViolations": [
          {
            "field": "events.events[0].user_data.user_identifiers[1]",
            "description": "The HEX encoded value is malformed.",
            "reason": "INVALID_HEX_ENCODING"
          },
          {
            "field": "events.events[1].user_data.user_identifiers[2]",
            "description": "The HEX encoded value is malformed.",
            "reason": "INVALID_HEX_ENCODING"
          }
        ]
      }
    ]
  }
}

QuotaFailure et RetryInfo

Recherchez les charges utiles QuotaFailure et RetryInfo lorsqu'une requête échoue avec RESOURCE_EXHAUSTED (code d'état HTTP 429).

Un message QuotaFailure indique qu'une ressource a été épuisée (par exemple, vous avez dépassé votre quota) ou qu'un système est surchargé. Examinez la liste des violations pour déterminer quels quotas ont été dépassés.

L'erreur peut également contenir un message RetryInfo, qui indique un retry_delay recommandé pour réessayer la requête.

RequestInfo

Recherchez la charge utile RequestInfo chaque fois qu'une requête échoue. Un RequestInfo contient le request_id qui identifie de manière unique votre requête API.

{
  "@type": "type.googleapis.com/google.rpc.RequestInfo",
  "requestId": "t-4490c640-dc5d-4c28-91c1-04a1cae0f49f"
}

Lorsque vous consignez des erreurs ou contactez l'assistance, veillez à inclure l'ID de la requête pour faciliter le diagnostic des problèmes.

ErrorInfo

Recherchez le message ErrorInfo pour obtenir des informations supplémentaires qui ne sont peut-être pas incluses dans les autres charges utiles de détails standards. La charge utile ErrorInfo contient une carte metadata avec des informations sur l'erreur.

Par exemple, voici le ErrorInfo pour un échec PERMISSION_DENIED causé par l'utilisation d'identifiants pour un projet Google Cloud dans lequel l'API Data Manager n'est pas activée. Le ErrorInfo fournit des informations supplémentaires sur l'erreur, telles que :

  • Projet associé à la requête, sous metadata.consumer.
  • Nom du service, sous metadata.serviceTitle.
  • URL où le service peut être activé, sous metadata.activationUrl.
{
  "error": {
    "code": 403,
    "message": "Data Manager API has not been used in project PROJECT_NUMBER before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.",
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "SERVICE_DISABLED",
        "domain": "googleapis.com",
        "metadata": {
          "consumer": "projects/PROJECT_NUMBER",
          "service": "datamanager.googleapis.com",
          "containerInfo": "PROJECT_NUMBER",
          "serviceTitle": "Data Manager API",
          "activationUrl": "https://console.developers.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER"
        }
      },
      ...
    ]
  }
}

Help et LocalizedMessage

Consultez les charges utiles Help et LocalizedMessage pour obtenir des liens vers la documentation et des messages d'erreur localisés qui vous aideront à comprendre et à corriger l'erreur.

Par exemple, voici les Help et LocalizedMessage pour un échec PERMISSION_DENIED causé par l'utilisation d'identifiants pour un projet Google Cloud dans lequel l'API Data Manager n'est pas activée. La charge utile Help indique l'URL permettant d'activer le service, et LocalizedMessage contient une description de l'erreur.

{
  "error": {
    "code": 403,
    "message": "Data Manager API has not been used in project PROJECT_NUMBER before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.",
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.LocalizedMessage",
        "locale": "en-US",
        "message": "Data Manager API has not been used in project PROJECT_NUMBER before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry."
      },
      {
        "@type": "type.googleapis.com/google.rpc.Help",
        "links": [
          {
            "description": "Google developers console API activation",
            "url": "https://console.developers.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER"
          }
        ]
      },
      ...
    ]
  }
}

Accéder aux détails des erreurs

Si vous utilisez l'une des bibliothèques clientes, utilisez les méthodes d'assistance pour obtenir les charges utiles de détails standards.

.NET

try {
    // Send API request
}
catch (Grpc.Core.RpcException rpcException)
{
    Console.WriteLine($"Exception encountered: {rpcException.Message}");
    var statusDetails =
        Google.Api.Gax.Grpc.RpcExceptionExtensions.GetAllStatusDetails(
            rpcException
        );
    foreach (var detail in statusDetails)
    {
        if (detail is Google.Rpc.BadRequest)
        {
            Google.Rpc.BadRequest badRequest = (Google.Rpc.BadRequest)detail;
            foreach (
                BadRequest.Types.FieldViolation? fieldViolation in badRequest.FieldViolations
            )
            {
                // Access attributes such as fieldViolation!.Reason and fieldViolation!.Field
            }
        }
        else if (detail is Google.Rpc.RequestInfo)
        {
            Google.Rpc.RequestInfo requestInfo = (Google.Rpc.RequestInfo)detail;
            string requestId = requestInfo.RequestId;
            // Log the requestId...
        }
        else if (detail is Google.Rpc.QuotaFailure)
        {
            Google.Rpc.QuotaFailure quotaFailure = (Google.Rpc.QuotaFailure)detail;
            foreach (
                Google.Rpc.QuotaFailure.Types.Violation violation in quotaFailure.Violations
            )
            {
                // Access attributes such as violation.Subject and violation.QuotaId
            }
        }
        else
        {
            // ...
        }
    }
}

Java

try {
  // Send API request
} catch (com.google.api.gax.rpc.InvalidArgumentException invalidArgumentException) {
  // Gets the standard BadRequest payload from the exception.
  BadRequest badRequest = invalidArgumentException.getErrorDetails().getBadRequest();
  for (int i = 0; i < badRequest.getFieldViolationsCount(); i++) {
    FieldViolation fieldViolation = badRequest.getFieldViolations(i);
    // Access attributes such as fieldViolation.getField() and fieldViolation.getReason()
  }

  // Gets the standard RequestInfo payload from the exception.
  RequestInfo requestInfo = invalidArgumentException.getErrorDetails().getRequestInfo();
  if (requestInfo != null) {
    String requestId = requestInfo.getRequestId();
    // Log the requestId...
  }
} catch (com.google.api.gax.rpc.QuotaFailureException quotaFailureException) {
  // Gets the standard QuotaFailure payload from the exception.
  QuotaFailure quotaFailure = quotaFailureException.getErrorDetails().getQuotaFailure();
  for (int i = 0; i < quotaFailure.getViolationsCount(); i++) {
    QuotaFailure.Violation violation = quotaFailure.getViolations(i);
    // Access attributes such as violation.getSubject() and violation.getQuotaId()
  }

  // Gets the standard RequestInfo payload from the exception.
  RequestInfo requestInfo = quotaFailureException.getErrorDetails().getRequestInfo();
  if (requestInfo != null) {
    String requestId = requestInfo.getRequestId();
    // Log the requestId...
  }
} catch (com.google.api.gax.rpc.ApiException apiException) {
  // Fallback exception handler for other types of ApiException.
  ...
}

Bonnes pratiques pour la gestion des erreurs

Pour créer des applications résilientes, mettez en œuvre les bonnes pratiques suivantes.

Examiner les détails des erreurs
Recherchez toujours l'une des charges utiles de détails standards, comme BadRequest. Chaque charge utile de détails standards contient des informations pour vous aider à comprendre la cause de l'erreur.
Distinguer les erreurs client de celles du serveur

Déterminez si l'erreur est due à un problème lié à votre implémentation (le client) ou à l'API (le serveur).

  • Erreurs du client : codes tels que INVALID_ARGUMENT, NOT_FOUND, PERMISSION_DENIED, FAILED_PRECONDITION et UNAUTHENTICATED. Elles nécessitent des modifications de la requête ou de l'état/des identifiants de votre application. Ne relancez pas la requête avant d'avoir résolu le problème.
  • Erreurs de serveur : codes tels que UNAVAILABLE, INTERNAL, DEADLINE_EXCEEDED et UNKNOWN. Cela suggère un problème temporaire avec le service d'API.
Implémenter une stratégie de nouvelles tentatives

Déterminez si l'erreur peut être corrigée et utilisez une stratégie de nouvelle tentative.

  • Ne relancez que les erreurs de serveur temporaires telles que UNAVAILABLE, DEADLINE_EXCEEDED, INTERNAL, UNKNOWN et ABORTED.
  • Utilisez un algorithme d'intervalle exponentiel entre les tentatives pour attendre des périodes de plus en plus longues entre les nouvelles tentatives. Cela permet d'éviter de surcharger un service déjà sollicité. Par exemple, attendez 1 s, puis 2 s, puis 4 s, et ainsi de suite jusqu'à atteindre un nombre maximal de tentatives ou un temps d'attente total.
  • Ajoutez une petite quantité aléatoire de "jitter" aux délais de backoff pour éviter le problème de "thundering herd" (troupeau tonnant) où de nombreux clients effectuent une nouvelle tentative simultanément.
Enregistrez les informations de manière exhaustive

Enregistrez la réponse d'erreur complète, y compris toutes les charges utiles de détails standards, en particulier l'ID de requête. Ces informations sont essentielles pour le débogage et pour signaler les problèmes à l'assistance Google si nécessaire.

Envoyer des commentaires aux utilisateurs

En vous basant sur les codes et les messages des charges utiles de détails standards, fournissez des commentaires clairs et utiles aux utilisateurs de votre application. Par exemple, au lieu de simplement dire "Une erreur s'est produite", vous pouvez dire "L'ID de transaction est manquant" ou "L'ID de compte de la destination est introuvable".

En suivant ces consignes, vous pourrez diagnostiquer et gérer efficacement les erreurs renvoyées par l'API Data Manager, ce qui vous permettra de créer des applications plus stables et conviviales.