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 API è fondamentale per creare applicazioni robuste in grado di gestire correttamente i problemi, dall'input non valido all'indisponibilità temporanea del servizio.

L'API Data Manager segue il modello di errore standard delle API di Google, basato sui 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.
  • Facoltativi, ulteriori dettagli sull'errore.

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 generale del tipo di errore. Devi 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 campo code 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 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 all'indirizzo error.status, mentre lo stato HTTP corrispondente si trova all'indirizzo 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 di 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, i payload BadRequest, QuotaFailure e RetryInfo sono utili per codici di errore specifici:

    • Se il codice di stato è INVALID_ARGUMENT, controlla il payload BadRequest per informazioni sui campi che hanno causato l'errore.
    • Se il codice di stato è RESOURCE_EXHAUSTED, controlla i payload QuotaFailure e RetryInfo per informazioni sulle quote e un consiglio sul ritardo dei tentativi.

Payload di dettagli standard

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

BadRequest

Controlla il payload BadRequest 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 scoprire quali campi contengono errori. Ogni voce field_violations contiene informazioni per aiutarti a 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 di un elenco (un campo repeated), il relativo indice viene mostrato tra parentesi quadre ([...]) dopo il nome dell'elenco.

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

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

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

Ecco un altro esempio di risposta a 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 nel secondo identificatore utente dell'evento.

  2. Il secondo event ha un valore che non è codificato in esadecimale nel 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"
          }
        ]
      }
    ]
  }
}

QuotaFailure e RetryInfo

Controlla i payload QuotaFailure e RetryInfo quando una richiesta non va a buon fine con RESOURCE_EXHAUSTED (codice di stato HTTP 429).

Un messaggio QuotaFailure indica che una risorsa è esaurita (ad esempio, hai superato la quota) o che un sistema è sovraccarico. Esamina l'elenco di violations per determinare quali quote sono state superate.

L'errore potrebbe contenere anche un messaggio RetryInfo, che indica un valore retry_delay consigliato per riprovare a inviare la richiesta.

RequestInfo

Controlla il payload RequestInfo ogni volta che una richiesta non va a buon fine. Un RequestInfo contiene l'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 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 di dettagli standard. Il payload ErrorInfo contiene una mappa metadata con informazioni sull'errore.

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

  • Il progetto associato alla richiesta, in metadata.consumer.
  • Il nome del servizio, in metadata.serviceTitle.
  • L'URL in cui è possibile attivare 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.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 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 Help e 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 attivare il servizio e 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.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"
          }
        ]
      },
      ...
    ]
  }
}

Accedere 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.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.
  ...
}

Best practice per la gestione degli errori

Per creare applicazioni resilienti, implementa le seguenti best practice.

Esaminare i dettagli dell'errore
Cerca sempre uno dei payload di dettagli standard, ad esempio BadRequest. Ogni payload dettagli standard contiene informazioni per aiutarti a 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 ripetizione dei tentativi

Determina se è possibile riprovare a eseguire l'operazione in caso di errore e utilizza una strategia di ripetizione.

  • Riprova solo in caso di errori del server temporanei come UNAVAILABLE, DEADLINE_EXCEEDED, INTERNAL, UNKNOWN e ABORTED.
  • Utilizza un algoritmo di backoff esponenziale per attendere periodi sempre più lunghi tra i tentativi. In questo modo si evita 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 tentativi o tempo di attesa totale.
  • Aggiungi un piccolo importo casuale di "jitter" ai ritardi di backoff per evitare il problema del "gregge fragoroso" in cui molti client riprovano contemporaneamente.
Registrare 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.

Fornire feedback degli utenti

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

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