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
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::collections::HashMap;

use async_trait::async_trait;

mod dummy_client;
#[cfg(test)]
mod test_client;
#[cfg(feature = "viaduct_client")]
mod viaduct_client;

pub(crate) use dummy_client::DummyClient;
#[cfg(test)]
pub(crate) use test_client::{TestHttpClient, TestResponse};
#[cfg(feature = "viaduct_client")]
pub use viaduct_client::ViaductClient;

// Re-exported so that consumers don't need depend on Url.
pub use url::Url;

/// A convenience type to represent raw HTTP headers.
pub type Headers = HashMap<String, String>;

/// HTTP method.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Method {
    GET,
    PATCH,
    POST,
    PUT,
    DELETE,
}

/// A response coming from an HTTP endpoint.
#[derive(Debug)]
pub struct Response {
    /// The HTTP status code of the response.
    pub status: u16,

    // The body of the response.
    pub body: Vec<u8>,

    // The headers of the response.
    pub headers: Headers,
}

impl Response {
    /// Whether or not the response code represents HTTP success.
    pub fn is_success(&self) -> bool {
        (200..=299).contains(&self.status)
    }

    /// Whether or not the response code represents HTTP client error.
    pub fn is_client_error(&self) -> bool {
        (400..=499).contains(&self.status)
    }

    /// Whether or not the response code represents HTTP server error.
    pub fn is_server_error(&self) -> bool {
        (500..=599).contains(&self.status)
    }
}

/// A description of a component used to perform an HTTP request.
#[async_trait]
pub trait Requester: std::fmt::Debug + Send + Sync {
    /// Perform an GET request toward the needed resource.
    ///
    /// # Arguments
    ///
    /// * `url` - the URL path to perform the HTTP GET on.
    async fn get(&self, url: Url) -> Result<Response, ()>;

    /// Perform a JSON request toward the needed resource.
    ///
    /// # Arguments
    ///
    /// * `method` - the HTTP method.
    /// * `url` - the URL path to perform the request.
    /// * `data` - the body content to send.
    /// * `headers` - the headers to send.
    async fn request_json(
        &self,
        method: Method,
        url: Url,
        data: Vec<u8>,
        headers: Headers,
    ) -> Result<Response, ()>;
}