Información sobre los errores de la API

En esta guía, se explica cómo la API de Data Manager controla y comunica los errores. Comprender la estructura y el significado de los errores de la API es fundamental para crear aplicaciones sólidas que puedan controlar los problemas de forma correcta, desde entradas no válidas hasta la falta de disponibilidad temporal del servicio.

La API de Data Manager sigue el modelo de error estándar de las APIs de Google, que se basa en los códigos de estado de gRPC. Cada respuesta de la API que genera un error incluye un objeto Status con lo siguiente:

  • Es un código de error numérico.
  • Es un mensaje de error.
  • Son detalles adicionales opcionales del error.

Códigos de error canónicos

La API de Data Manager usa un conjunto de códigos de error canónicos definidos por gRPC y HTTP. Estos códigos proporcionan una indicación de alto nivel del tipo de error. Siempre debes verificar este código primero para comprender la naturaleza fundamental del problema.

Para obtener más detalles sobre estos códigos, consulta Guía de diseño de APIs: Códigos de error.

Soluciona errores

Sigue estos pasos cuando falle una solicitud:

  1. Verifica el código de error para encontrar el tipo de error.

    • Si usas gRPC, el código de error se encuentra en el campo code de Status. Si usas una biblioteca cliente, es posible que arroje un tipo específico de excepción que corresponda al código de error. Por ejemplo, la biblioteca cliente para Java arroja un com.google.api.gax.rpc.InvalidArgumentException si el código de error es INVALID_ARGUMENT.
    • Si usas REST, el código de error se encuentra en la respuesta de error en error.status y el estado HTTP correspondiente se encuentra en error.code.
  2. Verifica la presencia de la carga útil de detalles estándar para el código de error. Las cargas útiles de detalles estándar son un conjunto de mensajes para los errores de las APIs de Google. Te brindan detalles de los errores de una manera estructurada y coherente. Cada error de la API de Data Manager puede tener varios mensajes de carga útil de detalles estándar. Las bibliotecas cliente de la API de Data Manager tienen métodos de ayuda para obtener las cargas útiles de detalles estándar de un error.

    Independientemente del código de error, te recomendamos que verifiques y registres las cargas útiles de ErrorInfo, RequestInfo, Help y LocalizedMessage.

    • ErrorInfo tiene información que podría no estar en otras cargas útiles.
    • RequestInfo tiene el ID de solicitud, que es útil si necesitas comunicarte con el equipo de asistencia.
    • Help y LocalizedMessage contienen vínculos y otros detalles para ayudarte a abordar el error.

    Además, las cargas útiles BadRequest, QuotaFailure y RetryInfo son útiles para códigos de error específicos:

    • Si el código de estado es INVALID_ARGUMENT, verifica la carga útil de BadRequest para obtener información sobre qué campos causaron el error.
    • Si el código de estado es RESOURCE_EXHAUSTED, consulta las cargas útiles de QuotaFailure y RetryInfo para obtener información sobre la cuota y una recomendación de demora para volver a intentarlo.

Cargas útiles de detalles estándar

Las cargas útiles de detalles estándar más comunes para la API de Data Manager son las siguientes:

BadRequest

Verifica la carga útil BadRequest cuando una solicitud falla con INVALID_ARGUMENT (código de estado HTTP 400).

Un mensaje BadRequest indica que la solicitud tenía campos con valores incorrectos o que faltaba un valor para un campo obligatorio. Revisa la lista field_violations en BadRequest para encontrar los campos que tienen errores. Cada entrada de field_violations tiene información para ayudarte a corregir el error:

field

Ubicación del campo en la solicitud, con una sintaxis de ruta de acceso en formato camel case.

Si una ruta de acceso apunta a un elemento de una lista (un campo repeated), su índice se muestra entre corchetes ([...]) después del nombre de la lista.

Por ejemplo, destinations[0].operating_account.account_id es el account_id en el operating_account del primer elemento de la lista destinations.

description

Es una explicación de por qué el valor causó un error.

reason

El enum ErrorReason, como INVALID_HEX_ENCODING o INVALID_CURRENCY_CODE.

Ejemplos de BadRequest

Esta es una respuesta de ejemplo para un error INVALID_ARGUMENT con un mensaje BadRequest. El field_violations que muestra el error es un accountId que no es un número. El valor field destinations[0].login_account.account_id muestra el accountId con un incumplimiento de campo en el login_account del primer elemento de la lista 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"
          }
        ]
      }
    ]
  }
}

Esta es otra respuesta de ejemplo de un error de INVALID_ARGUMENT con un mensaje de BadRequest. En este caso, la lista field_violations muestra dos errores:

  1. El primer event tiene un valor que no está codificado en hexadecimal en el segundo identificador del usuario del evento.

  2. El segundo event tiene un valor que no está codificado en hexadecimal en el tercer identificador de usuario del 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 y RetryInfo

Verifica las cargas útiles QuotaFailure y RetryInfo cuando una solicitud falla con RESOURCE_EXHAUSTED (código de estado HTTP 429).

Un mensaje QuotaFailure indica que se agotó un recurso (por ejemplo, superaste tu cuota) o que el sistema está sobrecargado. Inspecciona la lista de violations para determinar qué cuotas se superaron.

El error también puede contener un mensaje RetryInfo, que indica un retry_delay recomendado para reintentar la solicitud.

RequestInfo

Verifica la carga útil de RequestInfo cada vez que falle una solicitud. Un RequestInfo contiene el request_id que identifica de forma única tu solicitud a la API.

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

Cuando registres errores o te comuniques con el equipo de asistencia, asegúrate de incluir el ID de la solicitud para facilitar el diagnóstico de los problemas.

ErrorInfo

Verifica el mensaje ErrorInfo para recuperar información adicional que tal vez no se capture en las otras cargas útiles de detalles estándar. La carga útil de ErrorInfo contiene un mapa metadata con información sobre el error.

Por ejemplo, aquí se muestra el ErrorInfo para una falla de PERMISSION_DENIED causada por el uso de credenciales para un proyecto de Google Cloud en el que no está habilitada la API de Data Manager. El parámetro ErrorInfo proporciona información adicional sobre el error, como la siguiente:

  • Es el proyecto asociado a la solicitud, en metadata.consumer.
  • Nombre del servicio, en metadata.serviceTitle.
  • La URL en la que se puede habilitar el servicio, en 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 y LocalizedMessage

Verifica las cargas útiles Help y LocalizedMessage para obtener vínculos a la documentación y mensajes de error localizados que te ayuden a comprender y corregir el error.

Por ejemplo, aquí se muestran los campos Help y LocalizedMessage para un error de PERMISSION_DENIED causado por el uso de credenciales para un proyecto de Google Cloud en el que no está habilitada la API de Data Manager. La carga útil Help muestra la URL en la que se puede habilitar el servicio, y LocalizedMessage tiene una descripción del error.

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

Cómo acceder a los detalles del error

Si usas una de las bibliotecas cliente, usa los métodos auxiliares para obtener las cargas útiles de detalles estándar.

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

Prácticas recomendadas para el manejo de errores

Para crear aplicaciones resilientes, implementa las siguientes prácticas recomendadas.

Inspecciona los detalles del error
Siempre busca una de las cargas útiles de detalles estándar, como BadRequest. Cada carga útil de detalles estándar contiene información para ayudarte a comprender la causa del error.
Diferencia los errores del cliente de los errores del servidor

Determina si el error se debe a un problema con tu implementación (el cliente) o con la API (el servidor).

  • Errores del cliente: Códigos como INVALID_ARGUMENT, NOT_FOUND, PERMISSION_DENIED, FAILED_PRECONDITION y UNAUTHENTICATED. Estos errores requieren cambios en la solicitud o en el estado o las credenciales de tu aplicación. No vuelvas a intentar la solicitud sin solucionar el problema.
  • Errores del servidor: Códigos como UNAVAILABLE, INTERNAL, DEADLINE_EXCEEDED y UNKNOWN. Esto sugiere que hay un problema temporal con el servicio de la API.
Implementa una estrategia de reintento

Determina si se puede volver a intentar la solicitud y usa una estrategia de reintento.

  • Vuelve a intentarlo solo para errores transitorios del servidor, como UNAVAILABLE, DEADLINE_EXCEEDED, INTERNAL, UNKNOWN y ABORTED.
  • Usa un algoritmo de retirada exponencial para esperar períodos cada vez más largos entre los reintentos. Esto ayuda a evitar sobrecargar un servicio que ya está estresado. Por ejemplo, espera 1 s, luego 2 s, luego 4 s y así sucesivamente hasta alcanzar una cantidad máxima de reintentos o un tiempo de espera total.
  • Agrega una pequeña cantidad aleatoria de "fluctuación" a las demoras de la espera exponencial para evitar el problema de "activación simultánea", en el que muchos clientes vuelven a intentarlo de forma simultánea.
Registra a fondo

Registra la respuesta de error completa, incluidas todas las cargas útiles de detalles estándar, en especial el ID de solicitud. Esta información es fundamental para depurar y, si es necesario, informar problemas al equipo de asistencia de Google.

Proporciona comentarios de los usuarios

Según los códigos y mensajes de las cargas útiles de detalles estándar, proporciona comentarios claros y útiles a los usuarios de tu aplicación. Por ejemplo, en lugar de decir solo "Se produjo un error", puedes decir "Faltaba el ID de transacción" o "No se encontró el ID de la cuenta de destino".

Si sigues estos lineamientos, podrás diagnosticar y controlar de manera eficaz los errores que devuelve la API de Data Manager, lo que generará aplicaciones más estables y fáciles de usar.