Skip to main content

urlshortener/
request.rs

1#[cfg(feature = "client")]
2use reqwest::{
3    blocking::{Client, Response},
4    header::{self, HeaderMap, HeaderName, HeaderValue},
5};
6
7#[cfg(feature = "client")]
8const CONTENT_JSON: &str = "application/json";
9#[cfg(feature = "client")]
10const CONTENT_FORM_URL_ENCODED: &str = "application/x-www-form-urlencoded";
11
12/// An HTTP method abstraction
13#[derive(Debug, Copy, Clone)]
14pub enum Method {
15    /// `Get` HTTP method should be used.
16    Get,
17    /// `POST` HTTP method should be used.
18    Post,
19}
20
21/// An HTTP content type abstraction
22#[derive(Debug, Copy, Clone)]
23pub enum ContentType {
24    /// The url encoded form data header should be used.
25    FormUrlEncoded,
26    /// The json header should be used.
27    Json,
28}
29
30/// An HTTP user agent abstraction
31#[derive(Debug, Clone)]
32pub struct UserAgent(pub String);
33
34/// An abstraction for basic http request.
35#[derive(Debug, Clone)]
36pub struct Request {
37    /// The URL the request must be sent to.
38    pub url: String,
39    /// The request body.
40    pub body: Option<String>,
41    /// The content type.
42    pub content_type: Option<ContentType>,
43    /// The user agent.
44    pub user_agent: Option<UserAgent>,
45    /// Request headers as name-value pairs.
46    pub headers: Option<Vec<(String, String)>>,
47    /// The HTTP method.
48    pub method: Method,
49}
50
51#[cfg(feature = "client")]
52impl Request {
53    /// Sends the request and returns the response.
54    pub fn execute(&self, client: &Client) -> Result<Response, reqwest::Error> {
55        let mut builder = match self.method {
56            Method::Get => client.get(&self.url),
57            Method::Post => client.post(&self.url),
58        };
59
60        if let Some(agent) = self.user_agent.clone() {
61            builder = builder.header(header::USER_AGENT, agent.0);
62        }
63
64        if let Some(headers) = self.headers.clone() {
65            let mut map = HeaderMap::new();
66            for (name, value) in headers {
67                if let (Ok(n), Ok(v)) = (
68                    HeaderName::from_bytes(name.as_bytes()),
69                    HeaderValue::from_str(&value),
70                ) {
71                    map.insert(n, v);
72                }
73            }
74            builder = builder.headers(map);
75        }
76
77        if let Some(content_type) = self.content_type {
78            builder = match content_type {
79                ContentType::Json => builder.header(header::CONTENT_TYPE, CONTENT_JSON),
80                ContentType::FormUrlEncoded => {
81                    builder.header(header::CONTENT_TYPE, CONTENT_FORM_URL_ENCODED)
82                }
83            };
84        }
85
86        if let Some(body) = self.body.clone() {
87            builder = builder.body(body);
88        }
89
90        builder.send()
91    }
92}