gitignore_template_generator/http_client/
impls.rs

1use std::{collections::HashMap, time::Duration};
2
3use ureq::Agent;
4
5use crate::{ExitKind, ProgramExit, constant, http_client::api::HttpClient};
6
7/// Http client implementation relying on [`ureq`].
8#[derive(Default)]
9pub struct UreqHttpClient {
10    /// The base url of the HTTP server to reach.
11    ///
12    /// Used as base url when calling [`UreqHttpClient::get`] method.
13    pub server_url: String,
14}
15
16/// Http client implementation to mock a response.
17pub struct MockHttpClient {
18    /// The mocked response to be returned when calling [`MockHttpClient::get`]
19    /// method.
20    pub response: Result<String, ProgramExit>,
21}
22
23/// Http client implementation to mock a response.
24pub struct MockEndpointHttpClient<'a> {
25    /// The mocked response to be returned when calling [`MockHttpClient::get`]
26    /// method.
27    pub response: HashMap<&'a str, Result<String, ProgramExit>>,
28}
29
30impl HttpClient for UreqHttpClient {
31    /// Make a GET HTTP call using a [`ureq`] client.
32    ///
33    /// The server base url (i.e. https://localhost:8080) should be provided
34    /// as part of [`UreqHttpClient::server_url] field.
35    ///
36    /// See [`HttpClient::get`] for more infos.
37    fn get(&self, url: &str) -> Result<String, ProgramExit> {
38        let full_url = format!("{}{url}", self.server_url);
39        let agent: Agent = Agent::config_builder()
40            .timeout_global(Some(Duration::from_secs(5)))
41            .build()
42            .into();
43
44        let result = agent.get(full_url).call();
45
46        match result {
47            Ok(mut response) => match response.body_mut().read_to_string() {
48                Ok(body) => Ok(body.trim().to_string()),
49                Err(_error) => Err(ProgramExit {
50                    message: String::from(
51                        constant::error_messages::BODY_PARSING_ISSUE,
52                    ),
53                    exit_status: constant::exit_status::BODY_PARSING_ISSUE,
54                    styled_message: None,
55                    kind: ExitKind::Error,
56                }),
57            },
58            Err(error) => Err(ProgramExit {
59                message: constant::error_messages::API_CALL_FAILURE
60                    .replace("{error}", &error.to_string()),
61                exit_status: constant::exit_status::GENERIC,
62                styled_message: None,
63                kind: ExitKind::Error,
64            }),
65        }
66    }
67}
68
69impl HttpClient for MockHttpClient {
70    /// Returns the result linked to this instance.
71    ///
72    /// The given `_url` will not be used, simply a clone of linked
73    /// result will be returned.
74    fn get(&self, _url: &str) -> Result<String, ProgramExit> {
75        self.response.clone()
76    }
77}
78
79impl HttpClient for MockEndpointHttpClient<'_> {
80    /// Returns the result linked to the given url.
81    ///
82    /// The given `url` will only be used to get proper result from linked
83    /// hashmap.
84    fn get(&self, url: &str) -> Result<String, ProgramExit> {
85        self.response[url].clone()
86    }
87}