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
use crate::auth::AuthType;
use crate::request::{HttpMethod, NadeoRequest};
use crate::{Error, Result};
use reqwest::header::{HeaderMap, IntoHeaderName};
use serde::{Deserialize, Serialize};

/// Used for creating [`NadeoRequest`]s. <br>
/// The `URL`, [`HttpMethod`] and [`AuthType`] must be provided to successfully *build* a request.
///
/// [`NadeoRequest`]: NadeoRequest
/// [`HttpMethod`]: HttpMethod
/// [`AuthType`]: AuthType
pub struct NadeoRequestBuilder {
    auth_type: Option<AuthType>,
    url: Option<String>,
    method: Option<HttpMethod>,
    headers: HeaderMap,
}

impl Default for NadeoRequestBuilder {
    fn default() -> Self {
        NadeoRequestBuilder {
            auth_type: None,
            method: None,
            headers: HeaderMap::new(),
            url: None,
        }
    }
}

/// Error when the Request is invalid. For example if a required field is missing.
#[derive(thiserror::Error, Debug, Serialize, Deserialize)]
pub enum RequestBuilderError {
    #[error("no URL was provided")]
    MissingUrl,
    #[error("no HTTP method was provided")]
    MissingHttpMethod,
    #[error("no AuthType was provided")]
    MissingAuthType,
}

impl NadeoRequestBuilder {
    pub fn url(mut self, url: &str) -> Self {
        self.url = Some(url.to_string());

        self
    }

    pub fn method(mut self, method: HttpMethod) -> Self {
        self.method = Some(method);

        self
    }

    pub fn auth_type(mut self, auth_type: AuthType) -> Self {
        self.auth_type = Some(auth_type);

        self
    }

    /// Adds a header to the request. Adding a header should not be required in most cases.
    ///
    /// # Panics
    ///
    /// Panics if there is an error parsing the value.
    pub fn add_header<K>(mut self, key: K, val: &str) -> Self
    where
        K: IntoHeaderName,
    {
        self.headers.insert(key, val.parse().unwrap());
        self
    }

    /// Converts the `NadeoRequestBuilder` into a [`NadeoRequest`].
    /// The `URL`, [`HttpMethod`] and [`AuthType`] are required for a request.
    ///
    /// [`NadeoRequest`]: NadeoRequest
    /// [`HttpMethod`]: HttpMethod
    /// [`AuthType`]: AuthType
    pub fn build(self) -> Result<NadeoRequest> {
        if self.url.is_none() {
            return Err(Error::from(RequestBuilderError::MissingUrl));
        }
        if self.method.is_none() {
            return Err(Error::from(RequestBuilderError::MissingHttpMethod));
        }
        if self.auth_type.is_none() {
            return Err(Error::from(RequestBuilderError::MissingAuthType));
        }

        Ok(NadeoRequest {
            auth_type: self.auth_type.unwrap(),
            method: self.method.unwrap(),
            url: self.url.unwrap(),
            headers: self.headers,
        })
    }
}