1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
use schema::MangaDexErrorResponse;
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Error when parsing a URL.
///
/// This should not happen.
#[error("error parsing the URL")]
ParseUrlError(#[from] url::ParseError),
#[error("there was an error from the MangaDex servers (HTTP {0}): {1}")]
ServerError(u16, String),
#[error("failed to send a request to MangaDex: {0:?}")]
RequestError(#[from] reqwest::Error),
/// Error when building the request.
#[error("failed to build the request: {0:?}")]
BuilderError(#[from] derive_builder::UninitializedFieldError),
#[error("missing auth tokens; please log in to MangaDex")]
MissingTokens,
#[error("not a valid username: {0}")]
UsernameError(String),
#[error("not a valid password: {0}")]
PasswordError(String),
#[error("an error occurred while pinging the MangaDex server")]
PingError,
/// Errors returned from the MangaDex API request.
#[error("an error occurred with the MangaDex API request: {0:?}")]
Api(#[from] MangaDexErrorResponse),
/// Error while building the request struct.
#[error("failed to build a request: {0}")]
RequestBuilderError(String),
/// Error while parsing the type.
#[error("an error occurred while parsing the type: {0}")]
ParseError(String),
#[error(transparent)]
UnexpectedError(#[from] anyhow::Error),
}
pub mod schema {
use std::collections::HashMap;
use serde::Deserialize;
use uuid::Uuid;
#[derive(Debug, thiserror::Error, Deserialize)]
#[error("Bad request")]
pub struct MangaDexErrorResponse {
#[serde(default)]
pub errors: Vec<MangaDexError>,
}
#[derive(Debug, thiserror::Error, PartialEq, Eq, Deserialize, Clone)]
#[error("API error")]
pub struct MangaDexError {
pub id: Uuid,
/// HTTP status code.
pub status: u16,
/// Error title.
pub title: Option<String>,
/// Description about the error.
pub detail: Option<String>,
/// Provides insight into why the request failed.
///
/// # Captcha Errors (400)
///
/// The error may have been caused by one of the following:
///
/// - Captcha challenge result was wrong.
/// - The Captcha Verification service was down.
/// - Other, refer to the error message and the `errorCode` value.
///
/// # Rate Limit, Captcha Required (403)
///
/// Some endpoints may require captchas to proceed, in order to slow down automated malicious
/// traffic. Legitimate users might also be affected, based on the frequency of write requests
/// or due certain endpoints being particularly sensitive to malicious use, such as user signup.
///
/// Once an endpoint decides that a captcha needs to be solved,
/// a 403 Forbidden response will be returned, with the error code `captcha_required_exception`.
/// The sitekey needed for recaptcha to function is provided in both the
/// `X-Captcha-Sitekey` header field, as well as in the error context,
/// specified as `siteKey` parameter.
///
/// The captcha result of the client can either be passed into the repeated original request
/// with the `X-Captcha-Result` header or alternatively to the `POST /captcha/solve` endpoint.
/// The time a solved captcha is remembered varies across different endpoints and can also be
/// influenced by individual client behavior.
///
/// Authentication is not required for the `POST /captcha/solve` endpoint, captchas are tracked
/// both by client ip and logged in user id. If you are logged in, you want to send the session
/// token along, so you validate the captcha for your client ip and user id at the same time,
/// but it is not required.
// TODO: Use enum representations once the structure of this field is known.
// See: https://serde.rs/enum-representations.html
pub context: Option<HashMap<String, String>>,
}
}