Errores

En este capítulo se proporciona una descripción general del modelo de error de las API de Google y una guía general para los desarrolladores sobre cómo generar y manejar los errores de forma apropiada.

Las API de Google usan un modelo de error simple, independiente del protocolo, que nos permite exponer una experiencia coherente en diferentes API, protocolos de API como gRPC o HTTP y contextos de error (por ejemplo, errores asíncronos, de lotes o de flujo de trabajo).

Modelo de error

google.rpc.Status define el modelo de error de manera lógica y se muestra una instancia al cliente cuando se produce un error de API. En el siguiente fragmento de código, se muestra el diseño general del modelo de error:

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

Debido a que la mayoría de las API de Google usan un diseño de API orientado a los recursos, el manejo de errores sigue el mismo principio de diseño, ya que usa un conjunto pequeño de errores estándar con una gran cantidad de recursos. Por ejemplo, en lugar de definir las diferentes clases de errores del tipo “no se encontró”, el servidor usa un código de error estándar google.rpc.Code.NOT_FOUND y le comunica al cliente qué recurso no se encontró. El espacio de estado más pequeño reduce la complejidad de la documentación, permite mejorar las asignaciones idiomáticas en las bibliotecas cliente y reduce la complejidad de la lógica de los clientes sin restringir la inclusión de información práctica.

Códigos de error

Las API de Google deben usar los códigos de error canónicos definidos por google.rpc.Code. Las API individuales deben evitar la definición de códigos de error adicionales, ya que es muy poco probable que los desarrolladores escriban lógica con el fin de manejar una gran cantidad de códigos de error. Para referencia, manejar un promedio de 3 códigos de error por llamada a la API implica que la mayoría de la lógica de la aplicación se destine solo al manejo de errores, lo que no sería una buena experiencia para los desarrolladores.

Mensajes de error

El mensaje de error debe ayudar a los usuarios a comprender y resolver el error de la API de manera fácil y rápida. En general, ten en cuenta las siguientes pautas cuando escribas mensajes de error:

  • No supongas que el usuario es un experto en tu API. Los usuarios pueden ser desarrolladores de clientes, personal de operaciones, personal de TI o usuarios finales de aplicaciones.
  • No supongas que el usuario conoce la implementación del servicio o está familiarizado con el contexto de los errores (como el análisis de registros).
  • Cuando sea posible, los mensajes de error se deben construir de manera tal que un usuario técnico (pero no necesariamente un desarrollador de tu API) pueda responder al error y corregirlo.
  • Escribe un mensaje de error breve. Si es necesario, proporciona un vínculo en el que un lector que tenga dudas pueda hacer preguntas, hacer comentarios o recibir más información que no cabe de forma clara en un mensaje de error. De lo contrario, usa el campo de detalles para proporcionar más información.

Detalles de errores

Las API de Google definen un conjunto de cargas útiles de error estándar para los detalles de errores, que puedes encontrar en google/rpc/error_details.proto. Estas incluyen las necesidades más comunes de los errores de API, como las fallas de cuota y los parámetros no válidos. Al igual que los códigos de error, los detalles de errores deben usar estas cargas útiles estándar siempre que sea posible.

Los tipos de detalles de errores adicionales solo se deben ingresar si pueden ayudar al código de la aplicación a manejar los errores. Si solo las personas pueden manejar la información de errores, confía en el contenido del mensaje de error y permite que los desarrolladores lo manejen de forma manual en lugar de ingresar nuevos tipos de detalles de errores.

A continuación, se presentan algunos ejemplos de cargas útiles de error_details:

  • RetryInfo describe cuándo los clientes pueden reintentar una solicitud errónea, es posible que se muestre en Code.UNAVAILABLE o Code.ABORTED
  • QuotaFailure describe cómo falló una verificación de cuotas, es posible que se muestre en Code.RESOURCE_EXHAUSTED
  • BadRequest describe las infracciones en una solicitud del cliente, es posible que se muestre en Code.INVALID_ARGUMENT

Asignación HTTP

Mientras que los mensajes proto3 tienen codificación JSON nativa, la plataforma de la API de Google usa un esquema de error diferente para las API de REST y de JSON de Google por razones de compatibilidad con versiones anteriores.

Esquema:

// 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;
}

Ejemplo:

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

Asignación RPC

Los diferentes protocolos de RPC asignan el modelo de error de manera diferente. Para gRPC, el modelo de error es compatible de forma nativa con el código generado y la biblioteca del entorno de ejecución en cada lenguaje admitido. Puedes encontrar más información en la documentación de la API de gRPC (por ejemplo, consulta io.grpc.Status de gRPC con Java).

Asignación de bibliotecas cliente

Las bibliotecas cliente de Google pueden optar por mostrar errores de manera diferente en cada lenguaje para que sean coherentes con los idiomas establecidos. Por ejemplo, la biblioteca google-cloud-go mostrará un error que implemente la misma interfaz que google.rpc.Status, mientras que google-cloud-java generará una excepción.

Localización de errores

El campo message en google.rpc.Status está dirigido a los desarrolladores y debe estar en inglés.

Si se necesita un mensaje de error dirigido a los usuarios, usa google.rpc.LocalizedMessage como tu campo de detalles. Aunque el campo message en google.rpc.LocalizedMessage se puede localizar, asegúrate de que el campo message en google.rpc.Status esté en inglés.

De forma predeterminada, el servicio de API debe usar la configuración regional del usuario autenticado o el encabezado HTTP Accept-Language a fin de determinar el idioma para la localización.

Maneja los errores

A continuación, se muestra una tabla que contiene todos los códigos de error de gRPC definidos en google.rpc.Code y una descripción breve de las causas. Para manejar un error, puedes verificar la descripción del código de estado que se muestra y modificar tu llamada según corresponda.

HTTP RPC Descripción
200 OK No hay errores.
400 INVALID_ARGUMENT El cliente especificó un argumento no válido. Verifica el mensaje de error y los detalles de errores para obtener más información.
400 FAILED_PRECONDITION La solicitud no se puede ejecutar en el estado actual del sistema, como borrar un directorio que no esté vacío.
400 OUT_OF_RANGE El cliente especificó un rango no válido.
401 UNAUTHENTICATED La solicitud no se autenticó debido a que el token de OAuth no es válido, falta o se venció.
403 PERMISSION_DENIED El cliente no cuenta con los permisos necesarios. Esto puede suceder porque el token de OAuth no tiene los alcances correctos, el cliente no tiene permiso o la API no se habilitó para el proyecto del cliente.
404 NOT_FOUND No se encuentra un recurso específico o la solicitud se rechazó por razones no reveladas, como la lista blanca.
409 ABORTED Conflicto de simultaneidad, como conflicto del proceso de lectura, modificación y escritura.
409 ALREADY_EXISTS El recurso que el cliente intentó crear ya existe.
429 RESOURCE_EXHAUSTED Sin cuota de recursos o a punto de alcanzar el límite de frecuencia. Para obtener más información, el cliente debe buscar el detalle de error google.rpc.QuotaFailure.
499 CANCELLED El cliente canceló la solicitud.
500 DATA_LOSS Daño o pérdida de datos no recuperable. El cliente debe informar el error al usuario.
500 UNKNOWN Error de servidor desconocido. Por lo general, un error de servidor.
500 INTERNAL Error del servidor interno Por lo general, un error de servidor.
501 NOT_IMPLEMENTED El servidor no implementó el método de API.
503 UNAVAILABLE Servicio no disponible. Por lo general, el servidor no está en funcionamiento.
504 DEADLINE_EXCEEDED Se excedió el plazo de la solicitud. Esto ocurrirá solo si el emisor establece una fecha límite más corta que la fecha límite predeterminada del método (es decir, la fecha límite solicitada no es suficiente para que el servidor procese la solicitud) y la solicitud no finalizó dentro de la fecha límite.

Reintentos de error

Los clientes deben reintentar en los errores 500 y 503 con la retirada exponencial. El retraso mínimo debe ser de 1 s, a menos que se documente lo contrario. En el caso de los errores 429, el cliente puede reintentar con un retraso mínimo de 30 s. Para todos los demás errores, es posible que el reintento no sea aplicable. Primero, asegúrate de que tu solicitud sea idempotente y consulta el mensaje de error para obtener indicaciones.

Propagación de errores

Si tu servicio de API depende de otros servicios, no debes propagar los errores de esos servicios a tus clientes. Cuando se traducen errores, sugerimos lo siguiente:

  • Oculta los detalles de implementación y la información confidencial.
  • Configura la parte responsable del error. Por ejemplo, un servidor que recibe un error INVALID_ARGUMENT de otro servicio debe propagar un INTERNAL a su propio emisor.

Genera errores

Si eres un desarrollador de servidores, debes generar errores con información suficiente para ayudar a los desarrolladores cliente a comprender y resolver el problema. Al mismo tiempo, debes conocer la seguridad y la privacidad de los datos del usuario y evitar revelar información sensible en el mensaje y los detalles del error, ya que los errores a menudo se registran y otros pueden acceder a ellos. Por ejemplo, un mensaje de error como “La dirección IP de cliente no está en la lista blanca 128.0.0.0/8” muestra información sobre la política del lado del servidor, que puede no ser accesible para el usuario.

Si quieres generar errores apropiados, primero debes estar familiarizado con google.rpc.Code a fin de elegir el código de error más adecuado para cada condición de error. Una aplicación del servidor puede verificar varias condiciones de error en paralelo y mostrar la primera.

En la siguiente tabla, se enumera cada código de error y un ejemplo de un mensaje de error correcto.

HTTP RPC Ejemplo de mensaje de error
400 INVALID_ARGUMENT El campo de solicitud x.y.z es xxx, se esperaba uno de [yyy, zzz].
400 FAILED_PRECONDITION El recurso xxx no es un directorio vacío, por lo que no se puede borrar.
400 OUT_OF_RANGE El parámetro “edad” está fuera del rango [0, 125].
401 UNAUTHENTICATED Credenciales de autenticación no válidas.
403 PERMISSION_DENIED Permiso “xxx” denegado en el archivo “yyy”.
404 NOT_FOUND No se encontró el recurso “xxx”.
409 ABORTED No se pudo aplicar el bloqueo en el recurso “xxx”.
409 ALREADY_EXISTS El recurso “xxx” ya existe.
429 RESOURCE_EXHAUSTED Se excedió el límite de cuota “xxx”.
499 CANCELLED El cliente canceló la solicitud.
500 DATA_LOSS Consulta la nota.
500 UNKNOWN Consulta la nota.
500 INTERNAL Consulta la nota.
501 NOT_IMPLEMENTED No se implementó el método “xxx”.
503 UNAVAILABLE Consulta la nota.
504 DEADLINE_EXCEEDED Consulta la nota.

NOTA: Dado que el cliente no puede corregir el error del servidor, no es útil generar detalles de errores adicionales. Para evitar que se filtre información sensible en las condiciones de error, se recomienda no generar ningún mensaje de error y solo generar detalles de errores google.rpc.DebugInfo. El DebugInfo está diseñado solo para el registro del lado del servidor y no se debe enviar al cliente.

El paquete google.rpc define un conjunto de cargas útiles de error estándar, que se prefieren en lugar de las cargas de error personalizadas. En la siguiente tabla, se enumera cada código de error y su carga útil de error estándar coincidente, si corresponde.

HTTP RPC Detalle de error recomendado
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
¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...