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}