Erreurs

Ce chapitre les principaux aspects du modèle d'erreur pour les API Google. Il fournit également des conseils généraux aux développeurs sur la manière de générer et de gérer correctement les erreurs.

Les API Google utilisent un modèle d'erreur simple et indépendant du protocole, qui permet d'offrir une expérience cohérente dans différentes API, des protocoles d'API (tels que gRPC ou HTTP) et des contextes d'erreur (par exemple, erreurs asynchrones, par lots ou de workflow).

Modèle d'erreur

Le modèle d'erreur est défini de manière logique par google.rpc.Status, dont une instance est renvoyée au client lorsqu'une erreur d'API se produit. L'extrait de code suivant montre la conception générale du modèle d'erreur :

package google.rpc;

message Status {
  // A simple error code that can be easily handled by the client. The
  // actual error code is defined by `google.rpc.Code`.
  int32 code = 1;

  // A developer-facing human-readable error message in English. It should
  // both explain the error and offer an actionable resolution to it.
  string message = 2;

  // Additional error information that the client code can use to handle
  // the error, such as retry delay or a help link.
  repeated google.protobuf.Any details = 3;
}

Étant donné que la plupart des API Google utilisent une conception d'API axée sur les ressources, la gestion des erreurs suit le même principe de conception en utilisant un petit ensemble d'erreurs standards avec un grand nombre de ressources. Par exemple, au lieu de définir différents types d'erreurs "introuvables", le serveur utilise un code d'erreur google.rpc.Code.NOT_FOUND standard et indique au client quelle ressource spécifique est introuvable. Le plus petit espace d'état réduit la complexité de la documentation, offre de meilleurs mappages idiomatiques dans les bibliothèques clientes et réduit la complexité de la logique du client tout en ne limitant pas l'inclusion d'informations exploitables.

Codes d'erreur

Les API Google doivent utiliser les codes d'erreur canoniques définis par google.rpc.Code. Les API individuelles doivent éviter de définir des codes d'erreur supplémentaires, car il est très peu probable que les développeurs écrivent une logique pour gérer un grand nombre de codes d'erreur. Pour référence, gérer en moyenne trois codes d'erreur par appel d'API signifierait que la plupart des logiques d'application concernent la gestion des erreurs, ce qui n'entraînerait pas une bonne expérience pour les développeurs.

Messages d'erreur

Le message d'erreur devrait aider les utilisateurs à comprendre et résoudre l'erreur d'API facilement et rapidement. En général, tenez compte des instructions suivantes lors de la rédaction des messages d'erreur :

  • Ne supposez pas que l'utilisateur est un expert de votre API. Les utilisateurs peuvent être des développeurs clients, des opérateurs, du personnel informatique ou des utilisateurs finaux d'applications.
  • Ne partez pas du principe que l'utilisateur connaît la mise en œuvre de votre service ou qu'il connaît le contexte des erreurs (tel que l'analyse du journal).
  • Dans la mesure du possible, les messages d'erreur doivent être construits de manière à ce qu'un utilisateur technique (mais pas nécessairement un développeur de votre API) puisse répondre à l'erreur et la corriger.
  • Veillez à rédiger un message d'erreur concis. Si nécessaire, fournissez un lien permettant à un lecteur en difficulté de poser des questions, de faire des commentaires ou d’obtenir plus d’informations qui ne correspondent pas parfaitement à un message d’erreur. Sinon, utilisez le champ de détails pour développer.

Informations relatives à l'erreur

Les API Google définissent un ensemble de charges utiles d'erreur standard pour les informations relatives à l'erreur, que vous pouvez trouver dans google/rpc/error_details.proto. Elles couvrent les besoins les plus courants d'erreurs d'API, tels que les échecs de quota et les paramètres non valides. À l'instar des codes d'erreur, les développeurs doivent utiliser ces charges utiles standards dès que possible.

Certains types de détails d'erreur supplémentaires ne doivent être introduits que s'ils peuvent aider le code d'application à gérer les erreurs. Si les informations relatives à l'erreur ne peuvent être traitées que par des humains, utilisez le contenu du message d'erreur et laissez les développeurs le gérer manuellement plutôt que d'introduire des types de détails d'erreur supplémentaires.

Voici quelques exemples de charges utiles error_details :

  • RetryInfo : décrit quand les clients peuvent réessayer une requête ayant échoué. Elle peut être renvoyée dans Code.UNAVAILABLE ou Code.ABORTED.
  • QuotaFailure décrit comment une vérification de quota a échoué. Elle peut être renvoyée dans Code.RESOURCE_EXHAUSTED.
  • BadRequest : décrit les violations dans une requête client. Elle peut être renvoyée dans Code.INVALID_ARGUMENT.
  • ErrorInfo fournit des informations sur les erreurs structurées qui sont à la fois stables et extensibles.

Information sur l'erreur

ErrorInfo est l'une des charges utiles d'erreur standard. Il fournit des informations stables et extensibles sur lesquelles les humains et les applications peuvent dépendre. Chaque ErrorInfo comporte trois informations: un domaine d'erreur, un motif d'erreur et un ensemble de métadonnées d'erreur. Pour plus d'informations, consultez la définition ErrorInfo.

Mappage HTTP

Bien que les messages proto3 aient un codage JSON natif, la plate-forme d'API Google utilise un schéma d'erreur différent pour les API REST JSON de Google pour des raisons de rétrocompatibilité.

Schéma :

// The error schema for Google REST APIs. NOTE: this schema is not used for
// other wire protocols.
message Error {
  // This message has the same semantics as `google.rpc.Status`. It has an extra
  // field `status` for backward compatibility with Google API Client Library.
  message Status {
    // This corresponds to `google.rpc.Status.code`.
    int32 code = 1;
    // This corresponds to `google.rpc.Status.message`.
    string message = 2;
    // This is the enum version for `google.rpc.Status.code`.
    google.rpc.Code status = 4;
    // This corresponds to `google.rpc.Status.details`.
    repeated google.protobuf.Any details = 5;
  }
  // The actual error payload. The nested message structure is for backward
  // compatibility with Google API client libraries. It also makes the error
  // more readable to developers.
  Status error = 1;
}

Exemple :

{
  "error": {
    "code": 401,
    "message": "Request had invalid credentials.",
    "status": "UNAUTHENTICATED",
    "details": [{
      "@type": "type.googleapis.com/google.rpc.RetryInfo",
      ...
    }]
  }
}

Mappage RPC

Différents protocoles RPC mettent en correspondance le modèle d'erreur différemment. Pour gRPC, le modèle d'erreur est compatible de façon native par le code généré et la bibliothèque d'exécution dans chaque langage disponible. Pour en savoir plus, consultez la documentation de l'API de gRPC. Par exemple, consultez le statut Java io.grpc.Status de gRPC.

Mappage avec la bibliothèque cliente

Les bibliothèques clientes de Google peuvent choisir de relever les erreurs différemment selon les langages pour les rendre conformes aux idiomes établis. Par exemple, la bibliothèque google-cloud-go renvoie une erreur qui met en œuvre la même interface que google.rpc.Status, alors que google-cloud-java génère une exception.

Localisation des erreurs

Le champ message dans google.rpc.Status est destiné aux développeurs et doit être en anglais.

Si un message d'erreur adressé à l'utilisateur est nécessaire, utilisez google.rpc.LocalizedMessage en tant que champ de détails. Bien que le champ de message dans google.rpc.LocalizedMessage puisse être localisé, assurez-vous que ce même champ dans google.rpc.Status est en anglais.

Par défaut, le service d'API doit utiliser les paramètres régionaux ou l'en-tête Accept-Language de l'utilisateur authentifié pour déterminer la langue de la localisation.

Traiter les erreurs

Vous trouverez ci-dessous un tableau contenant tous les codes d'erreur gRPC définis dans google.rpc.Code et une brève description de leur origine. Pour gérer une erreur, vous pouvez vérifier la description du code d'état renvoyé et modifier votre appel en fonction.

HTTP RPC Description
200 OK Aucune erreur.
400 INVALID_ARGUMENT Le client a spécifié un argument incorrect. Consultez le message d'erreur et les détails de l'erreur pour plus d'informations.
400 FAILED_PRECONDITION La requête ne peut pas être exécutée dans l'état actuel du système, par exemple la suppression d'un répertoire non vide.
400 OUT_OF_RANGE Le client a spécifié une plage non valide.
401 UNAUTHENTICATED La requête n'a pas été authentifiée en raison d'un jeton OAuth manquant, non valide ou ayant expiré.
403 PERMISSION_DENIED Le client ne dispose pas d'une autorisation suffisante. Cela peut se produire lorsque le jeton OAuth ne dispose pas des champs d'application appropriés, car le client n'a pas d'autorisation ou car l'API n'a pas été activée pour le projet du client.
404 NOT_FOUND Une ressource spécifiée est introuvable ou la requête est rejetée pour des raisons non divulguées, telles que l'ajout à une liste blanche.
409 ABORTED Un conflit de simultanéité existe, tel qu'un conflit lecture-modification-écriture.
409 ALREADY_EXISTS La ressource qu'un client a essayé de créer existe déjà.
429 RESOURCE_EXHAUSTED Le quota de ressources est dépassé ou la limite du débit est atteinte. Pour plus d'informations, le client doit rechercher les détails de l'erreur google.rpc.QuotaFailure.
499 CANCELLED La demande a été annulée par le client.
500 DATA_LOSS Perte de données irrécupérable ou corruption de données. Le client doit signaler l'erreur à l'utilisateur.
500 UNKNOWN Erreur du serveur inconnue. Généralement un bug de serveur.
500 INTERNAL Erreur interne au serveur. Généralement un bug de serveur.
501 NOT_IMPLEMENTED Méthode d'API non mise en œuvre par le serveur.
503 UNAVAILABLE Service indisponible. Généralement, le serveur est inactif.
504 DEADLINE_EXCEEDED Délai de requête dépassé. Cela se produira uniquement si l'appelant définit un délai plus court que le délai par défaut de la méthode (le délai demandé ne suffit pas pour que le serveur traite la demande) et si la requête ne s'est pas terminée dans le délai.

Effectuer de nouvelles tentatives suite aux erreurs

Les clients peuvent effectuer de nouvelles tentatives à la suite d'erreurs de type "503 UNAVAILABLE" avec un intervalle exponentiel entre les tentatives. Le délai minimum doit être égal à 1 s sauf indication contraire.

Pour les erreurs de type "429 RESOURCE_EXHAUSTED", le client peut effectuer de nouvelles tentatives au niveau supérieur avec un délai minimal de 30 s. Ces tentatives ne sont utiles que pour les tâches en arrière-plan de longue durée.

Pour toutes les autres erreurs, il se peut que la nouvelle tentative ne s'applique pas. Assurez-vous d'abord que votre requête est idempotente et consultez la section google.rpc.RetryInfo pour obtenir des conseils.

Propager une erreur

Si votre service d'API dépend d'autres services, vous ne devez pas propager aveuglément les erreurs de ces services à vos clients. Lors de la traduction des erreurs, nous suggérons de suivre les conseils suivants :

  • Masquez les détails de mise en œuvre et les informations confidentielles.
  • Ajustez la partie responsable de l'erreur. Par exemple, un serveur qui reçoit une erreur INVALID_ARGUMENT d'un autre service doit propager un élément INTERNAL à son propre appelant.

Générer des erreurs

Si vous êtes un développeur de serveur, vous devez générer des erreurs avec suffisamment d'informations pour aider les développeurs du client à comprendre et à résoudre le problème. En même temps, vous devez être conscient de la sécurité et de la confidentialité des informations sur l'utilisateur et éviter de divulguer des informations sensibles dans le message d'erreur et les détails de l'erreur, car les erreurs sont souvent consignées et peuvent être accessibles par d'autres utilisateurs. Par exemple, un message d'erreur de type "L'adresse IP du client n'est pas sur la liste d'autorisation 128.0.0.0/8" expose des informations sur la stratégie côté serveur, auxquelles l'utilisateur peut ne pas accéder.

Pour générer des erreurs appropriées, vous devez d'abord connaître google.rpc.Code pour choisir le code d'erreur le mieux adapté à chaque condition d'erreur. Une application de serveur peut vérifier plusieurs conditions d'erreur en parallèle et renvoyer la première.

Le tableau suivant répertorie chaque code d'erreur et un exemple de message d'erreur correct.

HTTP RPC Exemple de message d'erreur
400 INVALID_ARGUMENT Le champ de requête xyz est xxx, le champ attendu doit être inclus dans la plage [yyy, zzz].
400 FAILED_PRECONDITION La ressource xxx est un répertoire non vide et ne peut donc pas être supprimée.
400 OUT_OF_RANGE Le paramètre "âge" est en dehors de la plage [0, 125].
401 UNAUTHENTICATED Identifiants d'authentification non valides.
403 PERMISSION_DENIED Autorisation "xxx" refusée sur la ressource "yyy".
404 NOT_FOUND Ressource 'xxx' introuvable.
409 ABORTED Impossible de verrouiller la ressource "xxx".
409 ALREADY_EXISTS La ressource "xxx" existe déjà.
429 RESOURCE_EXHAUSTED La limite du quota "xxx" est dépassée.
499 CANCELLED La demande a été annulée par le client.
500 DATA_LOSS Voir la remarque ci-dessous.
500 UNKNOWN Voir la remarque ci-dessous.
500 INTERNAL Voir la remarque ci-dessous.
501 NOT_IMPLEMENTED La méthode "xxx" n'a pas été mise en œuvre.
503 UNAVAILABLE Voir la remarque ci-dessous.
504 DEADLINE_EXCEEDED Voir la remarque ci-dessous.

Le package google.rpc définit un ensemble de charges utiles d'erreur standards, qui sont préférées aux charges utiles d'erreur personnalisées. Le tableau suivant répertorie chaque code d'erreur et sa charge utile d'erreur standard correspondante, le cas échéant.

HTTP RPC Informations sur l'erreur recommandées
400 INVALID_ARGUMENT google.rpc.BadRequest
400 FAILED_PRECONDITION google.rpc.PreconditionFailure
400 OUT_OF_RANGE google.rpc.BadRequest
401 UNAUTHENTICATED
403 PERMISSION_DENIED
404 NOT_FOUND google.rpc.ResourceInfo
409 ABORTED
409 ALREADY_EXISTS google.rpc.ResourceInfo
429 RESOURCE_EXHAUSTED google.rpc.QuotaFailure
499 CANCELLED
500 DATA_LOSS
500 UNKNOWN
500 INTERNAL
501 NOT_IMPLEMENTED
503 UNAVAILABLE
504 DEADLINE_EXCEEDED