helloasso/
error.rs

1//! Errors this crate can return
2
3use std::fmt::Display;
4
5use thiserror::Error;
6
7use serde::Deserialize;
8
9/// Errors that may occur when using the [client](crate::HelloAsso)
10///
11/// It can ether be a [Reqwest Error](reqwest::Error) or an [Authentication Error](crate::AuthenticationError)
12#[derive(Error, Debug)]
13#[non_exhaustive]
14pub enum Error {
15    #[error("request failed")]
16    ReqwestErr(#[from] reqwest::Error),
17    #[error("authentification failed")]
18    AuthErr(AuthenticationError),
19    #[error("your don't have the right permission")]
20    PermErr(AuthorizationError),
21    #[error("can't decode request")]
22    DecodeErr(reqwest::Error),
23    #[error("can't parse url")]
24    ParseUrlErr(url::ParseError),
25}
26
27/// Authentication Error that may occur when trying to access the api
28///
29/// `helloasso` will raise an [AuthenticationError](crate::AuthenticationError) {
30///     error: "unauthorized_client",
31///     error_description: "Invalid client_id '{client_id}'"
32/// } even when it is your `client_secret` witch is wrong.
33/// This behaviour is from the web api.
34#[derive(Error, Debug, Deserialize)]
35pub struct AuthenticationError {
36    pub error: String,
37    pub error_description: String,
38}
39
40impl Display for AuthenticationError {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        write!(f, "{}: {}", self.error, self.error_description)
43    }
44}
45
46/// Authorization Error that may occur when trying to access the api
47#[derive(Error, Debug, Deserialize)]
48pub struct AuthorizationError {
49    pub message: String,
50}
51
52impl Display for AuthorizationError {
53    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54        write!(f, "authorization error: {}", self.message)
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use crate::Error;
61    use std::error::Error as StdError;
62
63    fn error_trait_implemented<T>()
64    where
65        T: StdError,
66    {
67    }
68
69    #[test]
70    pub fn error_trait() {
71        error_trait_implemented::<Error>();
72    }
73}
74
75/*
76Note to myself:
77
78// TODO: Add test for PermErr, StatusCode::FORBIDDEN
79By implementing an endpoint and using a mocker (ie https://github.com/lipanski/mockito)
80We need to implement an endpoint first because the token url can't return a 401 or a 403
81
82Example code for AuthenticationError and AuthorizationError:
83
84StatusCode::UNAUTHORIZED => {
85    let error = response.json::<AuthorizationError>().await.map_err(|err| {
86        error!("Can't decode authentication error");
87        Error::DecodeErr(err)
88    })?;
89
90    error!("An authentication error as occur, wrong jwt");
91
92    Err(Error::AuthErr(error))
93}
94
95StatusCode::FORBIDDEN => {
96    let error = response.json::<AuthorizationError>().await.map_err(|err| {
97        error!("Can't decode authentication error");
98        Error::DecodeErr(err)
99    })?;
100
101    error!("Your JWT token hasn't the privileges or Roles for this action");
102
103    Err(Error::PermErr(error))
104}
105
106
107 */