use crate::{Code, Error};
impl Error {
pub fn internal(message: impl Into<String>) -> Self {
Self::new(Code::Internal, 500, message).with_retryable(false)
}
pub fn bad_request(message: impl Into<String>) -> Self {
Self::new(Code::BadRequest, 400, message).with_retryable(false)
}
pub fn validation(message: impl Into<String>) -> Self {
Self::new(Code::ValidationFailed, 400, message).with_retryable(false)
}
pub fn unauthorized(message: impl Into<String>) -> Self {
Self::new(Code::Unauthorized, 401, message).with_retryable(false)
}
pub fn forbidden(message: impl Into<String>) -> Self {
Self::new(Code::Forbidden, 403, message).with_retryable(false)
}
pub fn not_found(message: impl Into<String>) -> Self {
Self::new(Code::NotFound, 404, message).with_retryable(false)
}
pub fn method_not_allowed(message: impl Into<String>) -> Self {
Self::new(Code::MethodNotAllowed, 405, message).with_retryable(false)
}
pub fn request_timeout(message: impl Into<String>) -> Self {
Self::new(Code::RequestTimeout, 408, message).with_retryable(true)
}
pub fn conflict(message: impl Into<String>) -> Self {
Self::new(Code::Conflict, 409, message).with_retryable(false)
}
pub fn gone(message: impl Into<String>) -> Self {
Self::new(Code::Gone, 410, message).with_retryable(false)
}
pub fn payload_too_large(message: impl Into<String>) -> Self {
Self::new(Code::PayloadTooLarge, 413, message).with_retryable(false)
}
pub fn unprocessable_entity(message: impl Into<String>) -> Self {
Self::new(Code::UnprocessableEntity, 422, message).with_retryable(false)
}
pub fn rate_limited(message: impl Into<String>) -> Self {
Self::new(Code::RateLimited, 429, message).with_retryable(true)
}
pub fn timeout(message: impl Into<String>) -> Self {
Self::new(Code::Timeout, 504, message).with_retryable(true)
}
pub fn unavailable(message: impl Into<String>) -> Self {
Self::new(Code::Unavailable, 503, message).with_retryable(true)
}
pub fn downstream(service: impl Into<String>, cause: impl std::error::Error) -> Self {
let service = service.into();
let mut err = Self::wrap(Code::DownstreamError, 502, "", cause);
if !service.is_empty() {
err = err.with_details(serde_json::json!({"service": service}));
}
err.with_retryable(true)
}
pub fn downstream_timeout(service: impl Into<String>, cause: impl std::error::Error) -> Self {
let service = service.into();
let mut err = Self::wrap(Code::DownstreamTimeout, 504, "", cause);
if !service.is_empty() {
err = err.with_details(serde_json::json!({"service": service}));
}
err.with_retryable(true)
}
}
pub fn internalf(message: impl Into<String>) -> Error {
Error::internal(message)
}
pub fn bad_requestf(message: impl Into<String>) -> Error {
Error::bad_request(message)
}
pub fn not_foundf(message: impl Into<String>) -> Error {
Error::not_found(message)
}
pub fn unauthorizedf(message: impl Into<String>) -> Error {
Error::unauthorized(message)
}
pub fn forbiddenf(message: impl Into<String>) -> Error {
Error::forbidden(message)
}
pub fn conflictf(message: impl Into<String>) -> Error {
Error::conflict(message)
}
pub fn timeoutf(message: impl Into<String>) -> Error {
Error::timeout(message)
}
pub fn unavailablef(message: impl Into<String>) -> Error {
Error::unavailable(message)
}
use serde_json::json;
use std::collections::HashMap;
pub type FieldErrors = HashMap<String, String>;
pub fn validation(fields: FieldErrors) -> Error {
Error::new(Code::ValidationFailed, 400, "")
.with_details(json!({"fields": fields}))
.with_retryable(false)
}
pub fn from(err: impl std::error::Error + 'static) -> Error {
let err_str = err.to_string().to_lowercase();
if err_str.contains("timeout") || err_str.contains("timed out") {
return Error::timeout("");
}
if err_str.contains("cancel") {
return Error::new(Code::Canceled, 499, "").with_retryable(false);
}
Error::wrap(Code::Internal, 500, "", err).with_retryable(false)
}
pub fn is(err: &Error, code: Code) -> bool {
err.code == code
}