Erros
Todas as falhas lançam uma exceção. Uma classe para uma recusa, outra para a falta de resposta, e um id de pedido em cada erro da API.
Apanhar um
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? raiseendUm permission_error num envio é normalmente o âmbito de envio da CHAVE, um domínio ou um endereço que não lhe foi concedido, e não o espaço de trabalho, e é por isso que o exemplo imprime o que addresses.list_all diz que esta chave pode usar para enviar.
Cada tipo de recusa tem a sua própria subclasse, por isso um rescue pode escolher pela classe as que trata e deixar as restantes subir.
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}" raiseendAs classes
| Classe | Quando |
|---|---|
| OpenEmail::Error | A base de todos os erros que a gem define, por isso rescue OpenEmail::Error apanha-os todos. Não apanha ArgumentError. |
| OpenEmail::ApiError | A API respondeu, e não com um sucesso. Traz status, type, code, param, doc_url, request_id, retry_after_seconds, fields e body. É lançado tal como está quando type é api_error, como acontece com uma falha do servidor, e como a subclasse do seu type nos restantes casos. |
| OpenEmail::InvalidRequestError, AuthenticationError, PermissionError, NotFoundError, ConflictError, ValidationError e RateLimitError | Subclasses de ApiError, uma para cada type: invalid_request_error, authentication_error, permission_error, not_found_error, conflict_error, validation_error e rate_limit_error. |
| OpenEmail::NetworkError | Não chegou resposta: DNS, TLS, uma ligação recusada ou caída, ou o timeout. Traz original, a exceção subjacente, que é também a sua cause, e timeout? é true quando o timeout foi a razão. |
| OpenEmail::WebhookSignatureError | OpenEmail.verify_webhook_signature recusou uma entrega. |
| ArgumentError | Lançado antes de qualquer envio: uma chave em falta ou mal formada, um base_url: inutilizável, um id vazio. É a classe simples do Ruby, não um OpenEmail::Error, porque significa que a própria chamada está errada. |
O que um ApiError transporta
messageString- A frase da própria API, escrita para uma pessoa e que indica o valor problemático quando existe. Não é um identificador estável, por isso baseie a lógica em `code`.
statusInteger- O estado HTTP da resposta.
typeString- Um dos oito valores de `OpenEmail::ERROR_TYPES`, um conjunto congelado que não vai crescer. Quando o corpo não indica nenhum, é inferido a partir do estado.
codeString- A falha concreta, como `from_address_forbidden` ou `invalid_email_address`. É aberto e aditivo, por isso trate um que não reconheça como o seu `type`. É `unrecognised_response` quando o corpo não era o envelope de erro da API.
paramString or nil- O campo recusado, como caminho com pontos, por exemplo `to.0`, quando a falha indica um.
doc_urlString or nil- Uma página sobre esta falha, quando a API indica uma.
request_idString or nil- O id com que o servidor registou o pedido, vindo do corpo ou do cabeçalho `x-request-id`.
retry_after_secondsInteger, Float or nil- A espera que o servidor pediu em `Retry-After`, em segundos, quer tenha enviado um número ou uma data. nil quando não enviou nenhuma.
fieldsArray<Hash> or nil- Um Hash por problema, cada um com `key` e `error`, como `{key: "email", error: "email"}` quando `forms.subscribe` recusou as respostas com um 422 `invalid_form_submission`. nil quando o erro não lista nenhum.
bodyHash or nil- A resposta de erro completa, analisada, com chaves Symbol. nil quando estava vazia ou não era JSON.
| Predicado | True quando |
|---|---|
| auth? | type é authentication_error, um 401: sem chave, o tipo errado de credencial, ou uma chave que não emitimos. |
| permission? | permission_error, um 403: uma chave real sem o âmbito ou o endereço From de que precisa. |
| scope_missing? | code é insufficient_scope, o 403 que nomeia um âmbito em falta. |
| invalid_request? | invalid_request_error, um 400: um pedido que não pôde ser compreendido. Uma mensagem acima do limite de tamanho volta como um 422 message_too_large, por isso validation? é o predicado que a apanha. |
| validation? | validation_error, um 422: o esquema recusou-o, e param nomeia o campo. |
| not_found? | not_found_error, um 404: não existe tal recurso. |
| conflict? | conflict_error, um 409: o recurso já passou o ponto em que isto lhe podia ser feito. |
| rate_limited? | rate_limit_error, um 429. retry_after_seconds contém a espera quando o servidor indicou uma. |
| server_error? | status é 500 ou superior. Cite request_id se contactar o suporte. |
| retryable? | status é 408, 429, 500, 502, 503 ou 504. |
| step_up_required? | code é step_up_required, o 403 que um token de acesso OAuth recebe antes de uma alteração sensível até a pessoa ter verificado um código. |
A maioria dos predicados lê type, a metade congelada do envelope, e cada subclasse representa um type. code continua a ser uma String, porque a API garante que é aberto e aditivo, por isso trate um que não reconheça como o seu type. Uma lista fechada faria de uma atualização da gem o preço de ler um novo modo de falha.
Um corpo que não seja o envelope de erro da API lança na mesma um OpenEmail::ApiError, com type inferido a partir do estado e code definido como unrecognised_response. Um sucesso cujo corpo não seja JSON lança um também.
retryable? descreve o estado, não a sua chamada. Uma chamada que é seguro repetir já foi repetida quando lança a exceção, e um 429 como send_quota_exceeded ou ai_quota_exceeded falha da mesma forma até a sua quota ser reposta, por isso mostre-o a uma pessoa em vez de o repetir em ciclo.
Uma exceção que o seu adaptador lance torna-se um OpenEmail::NetworkError depois de esgotadas as repetições que a chamada permite, com a original em original e cause. NameError, TypeError e ArgumentError são a exceção à regra: significam um bug no adaptador, por isso são lançados sem alterações e nunca são repetidos.
request_id
Todos os OpenEmail::ApiError transportam o id de pedido que o servidor enviou, vindo do corpo do erro ou do cabeçalho x-request-id, e é a única coisa que liga a sua falha a uma linha no log do servidor. Um sucesso devolve apenas o corpo analisado, por isso não há nele nenhum id de pedido para ler.