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