Informazioni sugli errori API

Questa guida spiega come l'API Data Manager gestisce e comunica gli errori. Comprendere la struttura e il significato degli errori dell'API è fondamentale per creare applicazioni robuste in grado di gestire correttamente i problemi, dall'input non valido alla mancata disponibilità temporanea del servizio.

L'API Data Manager segue il modello di errore standard delle API di Google, basato su codici di stato gRPC. Ogni risposta API che genera un errore include un oggetto Status con:

  • Un codice di errore numerico.
  • Un messaggio di errore.
  • Dettagli di errore aggiuntivi facoltativi.

Codici di errore canonici

L'API Data Manager utilizza un insieme di codici di errore canonici definiti da gRPC e HTTP. Questi codici forniscono un'indicazione di alto livello del tipo di errore. Dovresti sempre controllare prima questo codice per comprendere la natura fondamentale del problema.

Per maggiori dettagli su questi codici, consulta la Guida alla progettazione delle API - Codici di errore.

Gestisci gli errori

Segui questi passaggi quando una richiesta non va a buon fine:

  1. Controlla il codice di errore per trovare il tipo di errore.

    • Se utilizzi gRPC, il codice di errore si trova nel code campo di Status. Se utilizzi una libreria client, potrebbe generare un tipo specifico di eccezione corrispondente al codice di errore. Ad esempio, la libreria client per Java genera un'eccezione com.google.api.gax.rpc.InvalidArgumentException se il codice di errore è INVALID_ARGUMENT.
    • Se utilizzi REST, il codice di errore si trova nella risposta di errore in error.status e il codice di stato HTTP corrispondente si trova in error.code.
  2. Controlla il payload dei dettagli standard per il codice di errore. I payload dei dettagli standard sono un insieme di messaggi per gli errori delle API di Google. Forniscono i dettagli degli errori in modo strutturato e coerente. Ogni errore dell'API Data Manager può avere più messaggi di payload dei dettagli standard. Le librerie client dell'API Data Manager hanno metodi helper per ottenere i payload dei dettagli standard da un errore.

    Indipendentemente dal codice di errore, ti consigliamo di controllare e registrare i payload ErrorInfo, RequestInfo, Help, e LocalizedMessage.

    • ErrorInfo contiene informazioni che potrebbero non essere presenti in altri payload.
    • RequestInfo contiene l'ID richiesta, utile se devi contattare l'assistenza.
    • Help e LocalizedMessage contengono link e altri dettagli per aiutarti a risolvere l'errore.

    Inoltre, il payload BadRequest è utile per gli errori INVALID_ARGUMENT perché fornisce informazioni sui campi che hanno causato l'errore.

Payload dei dettagli standard

I payload dei dettagli standard più comuni per l'API Data Manager sono:

BadRequest

Controlla il BadRequest payload quando una richiesta non va a buon fine con INVALID_ARGUMENT (codice di stato HTTP 400).

Un messaggio BadRequest indica che la richiesta conteneva campi con valori errati o che mancava un valore per un campo obbligatorio. Controlla l'elenco field_violations in BadRequest per trovare i campi con errori. Ogni voce field_violations contiene informazioni utili per correggere l'errore:

field

La posizione del campo nella richiesta, utilizzando una sintassi del percorso in camel case.

Se un percorso punta a un elemento in un elenco (un campo repeated), il relativo indice viene visualizzato tra parentesi quadre ([...]) dopo il nome dell'elenco.

Ad esempio, destinations[0].operating_account.account_id è l' account_id in operating_account del primo elemento nell' destinations elenco.

description

Una spiegazione del motivo per cui il valore ha causato un errore.

reason

L'enumerazione ErrorReason, ad esempio INVALID_HEX_ENCODING o INVALID_CURRENCY_CODE.

Esempi di BadRequest

Di seguito è riportata una risposta di esempio per un errore INVALID_ARGUMENT con un messaggio BadRequest. Le field_violations mostrano che l'errore è un accountId che non è un numero. Il valore field destinations[0].login_account.account_id mostra che accountId con una violazione del campo si trova in login_account del primo elemento nell'elenco 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"
          }
        ]
      }
    ]
  }
}

Di seguito è riportata un'altra risposta di esempio da un errore INVALID_ARGUMENT con un messaggio BadRequest. In questo caso, l'elenco field_violations mostra due errori:

  1. Il primo event ha un valore che non è codificato in esadecimale sul secondo identificatore utente dell'evento.

  2. Il secondo event ha un valore che non è codificato in esadecimale sul terzo identificatore utente dell'evento.

{
  "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"
          }
        ]
      }
    ]
  }
}

RequestInfo

Controlla il RequestInfo payload ogni volta che una richiesta non va a buon fine. Un RequestInfo contiene il request_id che identifica in modo univoco la tua richiesta API.

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

Quando registri gli errori o contatti l'assistenza, assicurati di includere l'ID richiesta per facilitare la diagnosi dei problemi.

ErrorInfo

Controlla il messaggio ErrorInfo per recuperare informazioni aggiuntive che potrebbero non essere acquisite negli altri payload dei dettagli standard. Il payload ErrorInfo contiene una mappa metadata con informazioni sull'errore.

Ad esempio, ecco l'ErrorInfo per un errore PERMISSION_DENIED causato dall'utilizzo delle credenziali per un progetto Google Cloud in cui l'API Data Manager non è abilitata. L'ErrorInfo fornisce informazioni aggiuntive sull'errore, ad esempio:

  • Il progetto associato alla richiesta, in metadata.consumer.
  • Il nome del servizio, in metadata.serviceTitle.
  • L'URL in cui è possibile abilitare il servizio, in 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.cloud.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.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER"
        }
      },
      ...
    ]
  }
}

Help e LocalizedMessage

Controlla i payload Help e LocalizedMessage per ottenere link alla documentazione e messaggi di errore localizzati che ti aiutano a comprendere e correggere l' errore.

Ad esempio, ecco l'Help e il LocalizedMessage per un errore PERMISSION_DENIED causato dall'utilizzo delle credenziali per un progetto Google Cloud in cui l'API Data Manager non è abilitata. Il payload Help mostra l'URL in cui è possibile abilitare il servizio e il LocalizedMessage contiene una descrizione dell'errore.

{
  "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.cloud.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.cloud.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 API Console API activation",
            "url": "https://console.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER"
          }
        ]
      },
      ...
    ]
  }
}

Accedi ai dettagli dell'errore

Se utilizzi una delle librerie client, utilizza i metodi helper per ottenere i payload dei dettagli standard.

.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.ErrorInfo)
        {
            Google.Rpc.ErrorInfo errorInfo = (Google.Rpc.ErrorInfo)detail;
            // Log the errorInfo.Reason and errorInfo.Metadata...

            // Log the details in the 'Metadata' map...
            foreach (
                KeyValuePair<String, String> metadataEntry in errorInfo.Metadata
            )
            {
                // Log the metadataEntry.Key and metadataEntry.Value...
            }
        }
        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.ApiException apiException) {
  // Fallback exception handler for other types of ApiException.

  // Gets the standard ErrorInfo payload from the exception.
  ErrorInfo errorInfo = apiException.getErrorDetails().getErrorInfo();
  // Log the 'reason' and 'domain'...

  // Log the details in the 'metadata' map...
  for (Entry<String, String> metadataEntry : errorInfo.getMetadataMap().entrySet()) {
    // Log the metadataEntry key and value...
  }

  // Gets the standard RequestInfo payload from the exception.
  RequestInfo requestInfo = invalidArgumentException.getErrorDetails().getRequestInfo();
  if (requestInfo != null) {
    String requestId = requestInfo.getRequestId();
    // Log the requestId...
  }
  ...
}

Best practice per la gestione degli errori

Per creare applicazioni resilienti, implementa le seguenti best practice.

Esamina i dettagli dell'errore
Cerca sempre uno dei payload dei dettagli standard come BadRequest. Ogni payload dei dettagli standard contiene informazioni utili per comprendere la causa dell'errore.
Distinguere gli errori del client da quelli del server

Determina se l'errore è causato da un problema con l'implementazione (il client) o con l'API (il server).

  • Errori del client: codici come INVALID_ARGUMENT, NOT_FOUND, PERMISSION_DENIED, FAILED_PRECONDITION, UNAUTHENTICATED. Questi richiedono modifiche alla richiesta o allo stato/alle credenziali dell'applicazione. Non riprovare a inviare la richiesta senza risolvere il problema.
  • Errori del server: codici come UNAVAILABLE, INTERNAL, DEADLINE_EXCEEDED, UNKNOWN. Questi suggeriscono un problema temporaneo con il servizio API.
Implementa una strategia di nuovi tentativi

Determina se è possibile riprovare a inviare la richiesta in caso di errore e utilizza una strategia di nuovi tentativi.

  • Riprova solo per gli errori del server temporanei come UNAVAILABLE, DEADLINE_EXCEEDED, INTERNAL, UNKNOWN e ABORTED.
  • Utilizza un algoritmo di backoff esponenziale per attendere periodi di tempo sempre più lunghi tra i nuovi tentativi. In questo modo, eviti di sovraccaricare un servizio già sotto stress. Ad esempio, attendi 1 secondo, poi 2 secondi, poi 4 secondi, continuando fino a un numero massimo di nuovi tentativi o al tempo di attesa totale.
  • Aggiungi una piccola quantità casuale di "jitter" ai ritardi di backoff per evitare il problema del "thundering herd", in cui molti client riprovano contemporaneamente.
Registra in modo completo

Registra la risposta di errore completa, inclusi tutti i payload dei dettagli standard, in particolare l'ID richiesta. Queste informazioni sono essenziali per il debug e la segnalazione di problemi all'assistenza Google, se necessario.

Fornisci feedback agli utenti

In base ai codici e ai messaggi nei payload dei dettagli standard, fornisci un feedback chiaro e utile agli utenti della tua applicazione. Ad esempio, anziché dire semplicemente "Si è verificato un errore", puoi dire "Mancava l'ID transazione" o "Non è stato trovato l'ID account della destinazione".

Se segui queste linee guida, puoi diagnosticare e gestire in modo efficace gli errori restituiti dall'API Data Manager, ottenendo applicazioni più stabili e di facile utilizzo.