Skip to main content

vynil_core/
http_mock.rs

1use crate::RhaiRes;
2use rhai::{Dynamic, Engine, Map};
3use serde::{Deserialize, Serialize};
4
5#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Default)]
6pub enum HttpMethod {
7    #[default]
8    Get,
9    Head,
10    Delete,
11    Patch,
12    Post,
13    Put,
14}
15
16#[derive(Deserialize, Serialize, Clone, Debug)]
17pub struct HttpMockItem {
18    pub path: String,
19    pub method: HttpMethod,
20    pub return_obj: Map,
21}
22
23#[derive(Clone, Debug)]
24pub struct RestClientMock {
25    baseurl: String,
26    mocks: Vec<HttpMockItem>,
27}
28impl RestClientMock {
29    #[must_use]
30    pub fn new(base: &str, mocks: Vec<HttpMockItem>) -> Self {
31        Self {
32            baseurl: base.to_string(),
33            mocks,
34        }
35    }
36
37    pub fn set_server_ca(&mut self, _ca: &str) {}
38
39    pub fn set_mtls(&mut self, _cert: &str, _key: &str) {}
40
41    pub fn headers_reset(&mut self) {}
42
43    pub fn add_header(&mut self, _key: String, _value: String) {}
44
45    pub fn add_header_json(&mut self) {}
46
47    pub fn add_header_bearer(&mut self, _token: &str) {}
48
49    pub fn add_header_basic(&mut self, _username: &str, _password: &str) {}
50
51    pub fn baseurl(&mut self, base: String) {
52        self.baseurl = base.to_string();
53    }
54
55    pub fn get(&mut self, path: String) -> RhaiRes<Map> {
56        let found: Vec<HttpMockItem> = self
57            .mocks
58            .clone()
59            .into_iter()
60            .filter(|m| m.method == HttpMethod::Get && m.path == path)
61            .collect();
62        if !found.is_empty() {
63            Ok(found[0].clone().return_obj)
64        } else {
65            Err(format!("Failed to find GET {path} in the Mock database").into())
66        }
67    }
68
69    pub fn head(&mut self, path: String) -> RhaiRes<Map> {
70        let found: Vec<HttpMockItem> = self
71            .mocks
72            .clone()
73            .into_iter()
74            .filter(|m| m.method == HttpMethod::Head && m.path == path)
75            .collect();
76        if !found.is_empty() {
77            Ok(found[0].clone().return_obj)
78        } else {
79            Err(format!("Failed to find HEAD {path} in the Mock database").into())
80        }
81    }
82
83    pub fn patch(&mut self, path: String, _val: Dynamic) -> RhaiRes<Map> {
84        let found: Vec<HttpMockItem> = self
85            .mocks
86            .clone()
87            .into_iter()
88            .filter(|m| m.method == HttpMethod::Patch && m.path == path)
89            .collect();
90        if !found.is_empty() {
91            Ok(found[0].clone().return_obj)
92        } else {
93            Err(format!("Failed to find PATCH {path} in the Mock database").into())
94        }
95    }
96
97    pub fn put(&mut self, path: String, _val: Dynamic) -> RhaiRes<Map> {
98        let found: Vec<HttpMockItem> = self
99            .mocks
100            .clone()
101            .into_iter()
102            .filter(|m| m.method == HttpMethod::Put && m.path == path)
103            .collect();
104        if !found.is_empty() {
105            Ok(found[0].clone().return_obj)
106        } else {
107            Err(format!("Failed to find PUT {path} in the Mock database").into())
108        }
109    }
110
111    pub fn post(&mut self, path: String, _val: Dynamic) -> RhaiRes<Map> {
112        let found: Vec<HttpMockItem> = self
113            .mocks
114            .clone()
115            .into_iter()
116            .filter(|m| m.method == HttpMethod::Post && m.path == path)
117            .collect();
118        if !found.is_empty() {
119            Ok(found[0].clone().return_obj)
120        } else {
121            Err(format!("Failed to find POST {path} in the Mock database").into())
122        }
123    }
124
125    pub fn post_form(&mut self, path: String, _val: Map) -> RhaiRes<Map> {
126        let found: Vec<HttpMockItem> = self
127            .mocks
128            .clone()
129            .into_iter()
130            .filter(|m| m.method == HttpMethod::Post && m.path == path)
131            .collect();
132        if !found.is_empty() {
133            Ok(found[0].clone().return_obj)
134        } else {
135            Err(format!("Failed to find POST {path} in the Mock database").into())
136        }
137    }
138
139    pub fn delete(&mut self, path: String) -> RhaiRes<Map> {
140        let found: Vec<HttpMockItem> = self
141            .mocks
142            .clone()
143            .into_iter()
144            .filter(|m| m.method == HttpMethod::Delete && m.path == path)
145            .collect();
146        if !found.is_empty() {
147            Ok(found[0].clone().return_obj)
148        } else {
149            Err(format!("Failed to find DELETE {path} in the Mock database").into())
150        }
151    }
152
153    pub fn delete_with_body(&mut self, path: String, _val: Dynamic) -> RhaiRes<Map> {
154        let found: Vec<HttpMockItem> = self
155            .mocks
156            .clone()
157            .into_iter()
158            .filter(|m| m.method == HttpMethod::Delete && m.path == path)
159            .collect();
160        if !found.is_empty() {
161            Ok(found[0].clone().return_obj)
162        } else {
163            Err(format!("Failed to find DELETE {path} in the Mock database").into())
164        }
165    }
166}
167
168pub fn httpmock_rhai_register(engine: &mut Engine, mocks: Vec<HttpMockItem>) {
169    let mocks = mocks.clone();
170    let new = move |base: &str| -> RestClientMock { RestClientMock::new(base, mocks.clone()) };
171    engine
172        .register_type_with_name::<RestClientMock>("RestClient")
173        .register_fn("new_http_client", new)
174        .register_fn("headers_reset", RestClientMock::headers_reset)
175        .register_fn("set_baseurl", RestClientMock::baseurl)
176        .register_fn("set_server_ca", RestClientMock::set_server_ca)
177        .register_fn("set_mtls_cert_key", RestClientMock::set_mtls)
178        .register_fn("add_header", RestClientMock::add_header)
179        .register_fn("add_header_json", RestClientMock::add_header_json)
180        .register_fn("add_header_bearer", RestClientMock::add_header_bearer)
181        .register_fn("add_header_basic", RestClientMock::add_header_basic)
182        .register_fn("head", RestClientMock::head)
183        .register_fn("get", RestClientMock::get)
184        .register_fn("http_get", RestClientMock::get)
185        .register_fn("delete", RestClientMock::delete)
186        .register_fn("http_delete", RestClientMock::delete)
187        .register_fn("delete_with_body", RestClientMock::delete_with_body)
188        .register_fn("http_delete_with_body", RestClientMock::delete_with_body)
189        .register_fn("patch", RestClientMock::patch)
190        .register_fn("http_patch", RestClientMock::patch)
191        .register_fn("post", RestClientMock::post)
192        .register_fn("http_post", RestClientMock::post)
193        .register_fn("put", RestClientMock::put)
194        .register_fn("http_put", RestClientMock::put)
195        .register_fn("post_form", RestClientMock::post_form)
196        .register_fn("http_post_form", RestClientMock::post_form)
197        .register_fn("headers_get", crate::http::headers_get)
198        .register_fn("headers_has", crate::http::headers_has);
199}