requestr_core/
lib.rs

1use log::{debug, info};
2use serde::{Deserialize, Serialize};
3use serde_yaml;
4use std::{
5    collections::{HashMap, HashSet},
6    fs, io,
7    path::PathBuf,
8};
9
10use thiserror::Error;
11
12mod template;
13
14pub use template::Template;
15
16#[derive(Error, Debug)]
17pub enum RequestrError {
18    #[error("Following parameter are missing from the input: {0:#?}")]
19    MissingParameter(Vec<String>),
20    #[error("Unable to load Template from {0}")]
21    OpeningTemplateFailed(String, io::Error),
22    #[error("Parsing template failed")]
23    TemplateParsingFailed(#[from] serde_yaml::Error),
24    #[error("Wrong request config: {0}")]
25    BrokenRequestConfig(String),
26    #[error("Request failed")]
27    UnknownRequestError(#[from] reqwest::Error),
28    #[error("Unknown Requestr Error")]
29    Unknown,
30}
31
32pub type ResultT<T> = Result<T, RequestrError>;
33
34fn default_header() -> HashMap<String, String> {
35    HashMap::new()
36}
37
38#[derive(Debug, PartialEq, Serialize, Deserialize)]
39pub struct RequestConfig {
40    pub url: String,
41    #[serde(default = "default_header")]
42    pub header: HashMap<String, String>,
43    pub body: Option<String>,
44    pub method: Option<String>,
45}
46
47pub fn load_request_template(filename: &PathBuf) -> ResultT<Template> {
48    let contents = match fs::read_to_string(filename) {
49        Ok(contents) => contents,
50        Err(err) => {
51            return Err(RequestrError::OpeningTemplateFailed(
52                filename.to_string_lossy().to_string(),
53                err,
54            ))
55        }
56    };
57
58    let request_config_template = Template::new(contents.as_str());
59    debug!("{:#?}", request_config_template);
60
61    Ok(request_config_template)
62}
63
64pub fn validate_parameter(template: &Template, parameter: &HashMap<String, String>) -> ResultT<()> {
65    debug!("{:#?}", parameter);
66
67    let provided_names: HashSet<_> = parameter.keys().cloned().collect();
68    let names: HashSet<_> = template.names.iter().cloned().collect();
69
70    let from_input: HashSet<_> = provided_names.difference(&names).collect();
71    let from_template: HashSet<_> = names.difference(&provided_names).collect();
72
73    if from_input.len() > 0 {
74        info!(
75            "Following parameters are defined but not used: {:?}",
76            from_input
77        );
78    }
79
80    if from_template.len() > 0 {
81        Err(
82            RequestrError::MissingParameter(from_template.into_iter().map(|p| p.clone()).collect())
83                .into(),
84        )
85    } else {
86        Ok(())
87    }
88}
89
90pub fn load_request_definition(
91    template: &Template,
92    parameter: &HashMap<String, String>,
93) -> ResultT<RequestConfig> {
94    let request_config_string = template.render(parameter);
95
96    let request_config: RequestConfig = serde_yaml::from_str(request_config_string.as_str())?;
97
98    debug!("{:#?}", request_config);
99
100    Ok(request_config)
101}
102
103pub fn make_request(
104    url: &str,
105    body: Option<String>,
106    method: Option<String>,
107    header: HashMap<String, String>,
108) -> ResultT<String> {
109    let client = reqwest::blocking::Client::new();
110
111    let request_builder = match method.unwrap_or("GET".to_string()).to_uppercase().as_str() {
112        "DELETE" => client.delete(url),
113        "GET" => client.get(url),
114        "POST" => client.post(url),
115        "PUT" => client.put(url),
116        "PATCH" => client.put(url),
117        method => {
118            return Err(RequestrError::BrokenRequestConfig(format!(
119                "Unknown http method: {}",
120                method
121            )))
122        }
123    };
124
125    let request_builder = match body {
126        Some(body) => request_builder.body(body),
127        None => request_builder,
128    };
129
130    let request_builder = header
131        .into_iter()
132        .fold(request_builder, |request_builder, (name, value)| {
133            request_builder.header(name.as_str(), value.as_str())
134        });
135
136    let response = request_builder.send()?;
137
138    debug!("{:#?}", response);
139
140    let response_body = response.text()?;
141
142    Ok(response_body)
143}
144
145#[cfg(test)]
146mod tests {
147    #[test]
148    fn it_works() {
149        assert_eq!(2 + 2, 4);
150    }
151}