Ir a la documentación
Ruby

Errores

Todo fallo lanza una excepción. Una clase para un rechazo, otra para la falta de respuesta, y un id de solicitud en cada error de la API.

Capturar uno

rescue_errors.rb
message = {from: "[email protected]", to: "[email protected]", subject: "Your September invoice", text: "Invoice attached."} begin  client.emails.send(message)rescue OpenEmail::ApiError => error  warn "#{error.code} #{error.param} #{error.message}" if error.validation?  warn client.addresses.list_all.addresses.inspect if error.permission?  warn "try again in #{error.retry_after_seconds} seconds" if error.rate_limited?   warn "#{error.status} #{error.request_id}"  raiserescue OpenEmail::NetworkError => error  warn "no answer in time" if error.timeout?  raiseend

Un permission_error en un envío suele deberse al ámbito de envío de la CLAVE, a un dominio o a una dirección que no se le concedió, y no al espacio de trabajo, y por eso el ejemplo imprime lo que dice addresses.list_all sobre las direcciones con las que puede enviar esta clave.

Cada tipo de rechazo tiene su propia subclase, así que un rescue puede elegir por clase los que gestiona y dejar que el resto siga subiendo.

rescue_by_class.rb
message = {from: "[email protected]", to: "[email protected]", subject: "Your September invoice", text: "Invoice attached."} begin  client.emails.send(message)rescue OpenEmail::ValidationError => error  warn "#{error.param}: #{error.message}"rescue OpenEmail::AuthenticationError, OpenEmail::PermissionError => error  warn "the key cannot do this: #{error.code}"  raiserescue OpenEmail::Error => error  warn "#{error.class}: #{error.message}"  raiseend

Las clases

ClaseCuándo
OpenEmail::ErrorLa base de todos los errores que define la gema, así que rescue OpenEmail::Error los captura todos. No captura ArgumentError.
OpenEmail::ApiErrorLa API respondió, y no con un éxito. Lleva status, type, code, param, doc_url, request_id, retry_after_seconds, fields y body. Se lanza tal cual cuando type es api_error, como ocurre con un fallo del servidor, y como la subclase de su type en los demás casos.
OpenEmail::InvalidRequestError, AuthenticationError, PermissionError, NotFoundError, ConflictError, ValidationError y RateLimitErrorSubclases de ApiError, una por cada type: invalid_request_error, authentication_error, permission_error, not_found_error, conflict_error, validation_error y rate_limit_error.
OpenEmail::NetworkErrorNo llegó ninguna respuesta: DNS, TLS, una conexión rechazada o cortada, o el tiempo de espera. Lleva original, la excepción subyacente, que también es su cause, y timeout? es true cuando el motivo fue el tiempo de espera.
OpenEmail::WebhookSignatureErrorOpenEmail.verify_webhook_signature rechazó una entrega.
ArgumentErrorSe lanza antes de enviar nada: una clave ausente o mal formada, un base_url: inutilizable, un id vacío. Es la clase de Ruby normal, no un OpenEmail::Error, porque significa que la propia llamada es incorrecta.

Lo que lleva un ApiError

messageString
La frase de la propia API, escrita para una persona y que nombra el valor problemático cuando lo hay. No es un identificador estable, así que usa `code` para ramificar.
statusInteger
El status HTTP de la respuesta.
typeString
Uno de los ocho valores de `OpenEmail::ERROR_TYPES`, un conjunto congelado que no crecerá. Cuando el cuerpo no nombra ninguno, se infiere a partir del status.
codeString
El fallo concreto, como `from_address_forbidden` o `invalid_email_address`. Es abierto y aditivo, así que trata uno que no reconozcas según su `type`. Vale `unrecognised_response` cuando el cuerpo no era el sobre de error de la API.
paramString or nil
El campo rechazado, como ruta con puntos, por ejemplo `to.0`, cuando el fallo nombra uno.
doc_urlString or nil
Una página sobre este fallo, cuando la API indica una.
request_idString or nil
El id con el que el servidor registró la solicitud, tomado del cuerpo o de la cabecera `x-request-id`.
retry_after_secondsInteger, Float or nil
La espera que pidió el servidor en `Retry-After`, en segundos, tanto si envió un número como una fecha. nil cuando no envió ninguna.
fieldsArray<Hash> or nil
Un Hash por problema, cada uno con `key` y `error`, como `{key: "email", error: "email"}` cuando `forms.subscribe` rechazó las respuestas con un 422 `invalid_form_submission`. nil cuando el error no enumera ninguno.
bodyHash or nil
La respuesta de error completa, analizada, con claves Symbol. nil cuando estaba vacía o no era JSON.
PredicadoTrue cuando
auth?type es authentication_error, un 401: sin clave, un tipo de credencial equivocado o una clave que no emitimos nosotros.
permission?permission_error, un 403: una clave real sin el scope o sin la dirección From que necesita.
scope_missing?code es insufficient_scope, el 403 que nombra un scope que falta.
invalid_request?invalid_request_error, un 400: una solicitud que no se pudo entender. Un mensaje que supera el límite de tamaño vuelve como un 422 message_too_large, así que validation? es el predicado que lo captura.
validation?validation_error, un 422: el esquema lo rechazó, y param nombra el campo.
not_found?not_found_error, un 404: no existe ese recurso.
conflict?conflict_error, un 409: el recurso ha pasado el punto en el que se le podía hacer esto.
rate_limited?rate_limit_error, un 429. retry_after_seconds contiene la espera cuando el servidor indicó una.
server_error?status es 500 o superior. Cita request_id si contactas con soporte.
retryable?status es 408, 429, 500, 502, 503 o 504.
step_up_required?code es step_up_required, el 403 que recibe un token de acceso OAuth antes de un cambio delicado hasta que la persona haya verificado un código.

La mayoría de los predicados leen type, la mitad congelada del sobre, y cada subclase representa un type. code sigue siendo una String, porque la API garantiza que es abierto y aditivo, así que trata uno que no reconozcas según su type. Una lista cerrada convertiría una actualización de la gema en el precio de leer un nuevo modo de fallo.

Un cuerpo que no es el sobre de error de la API lanza igualmente un OpenEmail::ApiError, con type inferido a partir del status y code fijado en unrecognised_response. Una respuesta correcta cuyo cuerpo no sea JSON también lanza uno.

retryable? describe el status, no tu llamada. Una llamada que se puede repetir sin riesgo ya se ha reintentado cuando lanza el error, y un 429 como send_quota_exceeded o ai_quota_exceeded falla igual hasta que se restablece su cupo, así que muéstraselo a una persona en lugar de repetirlo en bucle.

Una excepción que lanza tu adaptador se convierte en un OpenEmail::NetworkError una vez agotados los reintentos que permita la llamada, con la original en original y cause. NameError, TypeError y ArgumentError son la excepción a la regla: indican un error de programación en el adaptador, así que se lanzan sin cambios y nunca se reintentan.

request_id

Todo OpenEmail::ApiError lleva el id de solicitud que envió el servidor, tomado del cuerpo del error o de la cabecera x-request-id, y es lo único que vincula tu fallo con una línea del registro del servidor. Una respuesta correcta devuelve solo el cuerpo analizado, así que en ella no hay ningún id de solicitud que leer.