esi_openapi/errors.rs
1//! Errors
2
3use http::header::ToStrError;
4use std::num::ParseIntError;
5use thiserror::Error;
6
7/// Errors that can occur when dealing with ESI.
8#[derive(Debug, Error)]
9#[non_exhaustive]
10pub enum EsiError {
11 /// Error that can be thrown if the `EsiBuilder` struct is
12 /// invalid when `.build()` is called.
13 #[error("Missing required builder struct value '{0}'")]
14 EmptyClientValue(String),
15 /// Error that can be thrown if the `EsiBuilder` struct is
16 /// invalid when `.build()` is called.
17 /// You need to specify either a client secret or enable application auth
18 #[error("Authentication flow information missing. You need to either specify client_secret or enable application auth.")]
19 MissingAuthenticationFlowInformation,
20 /// You have to retrieve the ESI spec via `Esi::update_spec`
21 /// before making this call.
22 #[error("Missing spec")]
23 EmptySpec,
24 /// Error that could be thrown if the access token JWT from SSO
25 /// is invalid, whether due to tampering or some other reason.
26 #[error("Invalid JWT: {0}")]
27 InvalidJWT(String),
28 /// Validation of the JWT failed.
29 #[cfg(feature = "validate_jwt")]
30 #[error("JWT validation failed")]
31 JwtValidationFailed(#[from] jsonwebtoken::errors::Error),
32 /// Error that can be thrown by any function that makes HTTP
33 /// calls our to external resources for response codes that
34 /// aren't valid as defined [by reqwest].
35 /// [by reqwest]: https://docs.rs/reqwest/0.10.6/reqwest/struct.StatusCode.html#method.is_success
36 #[error("Invalid HTTP status code received: {0}")]
37 InvalidStatusCode(u16),
38 /// Error for if the provided user-agent header value has invalid characters.
39 #[error("Invalid HTTP header value")]
40 InvalidUserAgentHeader(#[from] http::header::InvalidHeaderValue),
41 /// Error for if the underlying `reqwest::Client` could not be constructed.
42 #[error("HTTP client error: {0}")]
43 ReqwestError(#[from] reqwest::Error),
44 /// Error for if the String cannot be converted into a valid HTTP method.
45 #[error("Invalid HTTP method")]
46 HttpMethodError(#[from] http::method::InvalidMethod),
47 /// Error for if a request is made to an endpoint that requires authentication,
48 /// but no access token is present in the Esi struct.
49 #[error("This endpoint requires an access token")]
50 MissingAuthentication,
51 /// Error for not finding the passed operationId in the ESI OpenAPI spec.
52 #[error("Could not resolve operationId '{0}' to a URL path")]
53 UnknownOperationID(String),
54 /// Error for being unable to parse the OpenAPI spec from ESI.
55 #[error("Error occurred while parsing the OpenAPI spec at: {0}")]
56 FailedSpecParse(String),
57 /// Error for being unable to parse JSON from anywhere.
58 #[error("Failed to serialize/deserialize JSON; this may be due to unexpected data or invalid struct field(s)")]
59 FailedJsonParse(#[from] serde_json::Error),
60 /// Error for being unable to get the current timestamp.
61 #[error("Could not get current timestamp: {0}")]
62 Timestamp(#[from] std::time::SystemTimeError),
63 /// Error for being unable to read response header.
64 #[error("Could not read response header value: {0}")]
65 HeaderReadError(#[from] ToStrError),
66 /// Error for being unable to parse header value.
67 #[error("Could not parse response header - {0}: {1}")]
68 HeaderParseError(String, ParseIntError),
69 /// Error for enforcing ESI error limit
70 #[error("Refusing to process request as we are error limited for {0}ms")]
71 ErrorLimited(i64),
72 /// ESI answered `429 Too Many Requests`: the rate-limit bucket for this
73 /// route group is empty. Wait `retry_after_secs` (from the `Retry-After`
74 /// header, when present) before calling routes in `group` again.
75 #[error("Rate limited by ESI (group: {group:?}, retry after: {retry_after_secs:?}s)")]
76 RateLimited {
77 /// Rate-limit group from the `X-Ratelimit-Group` header, if present.
78 group: Option<String>,
79 /// Seconds to wait, from the `Retry-After` header, if present.
80 retry_after_secs: Option<u64>,
81 },
82 /// Error for the access token being used after expiring (and therefore
83 /// being unable to be used for ESI) and no refresh token being present
84 /// to fetch another access token.
85 #[error("Access token is expired, and no refresh token is present")]
86 AccessTokenExpired,
87 /// Error when a access_token needs to be refreshed, but no refresh
88 /// token could be found to refresh the access token
89 #[error("No refresh token available to request an access token")]
90 NoRefreshTokenAvailable,
91}
92
93/// Crate `Result` wrapper.
94pub type EsiResult<T> = Result<T, EsiError>;