1pub fn coerce_value(raw: &str) -> serde_json::Value {
18 if raw.is_empty() {
19 return serde_json::Value::Null;
20 }
21
22 if raw.eq_ignore_ascii_case("true") {
23 return serde_json::Value::Bool(true);
24 }
25 if raw.eq_ignore_ascii_case("false") {
26 return serde_json::Value::Bool(false);
27 }
28 if raw.eq_ignore_ascii_case("null") {
29 return serde_json::Value::Null;
30 }
31
32 if let Ok(n) = raw.parse::<i64>() {
33 return serde_json::Value::Number(n.into());
34 }
35
36 if let Ok(f) = raw.parse::<f64>() {
37 if f.is_finite() {
38 if let Some(n) = serde_json::Number::from_f64(f) {
39 return serde_json::Value::Number(n);
40 }
41 }
42 }
43
44 serde_json::Value::String(raw.to_string())
45}
46
47pub fn parse_query_string(query: &str) -> serde_json::Map<String, serde_json::Value> {
52 let mut map = serde_json::Map::new();
53
54 if query.is_empty() {
55 return map;
56 }
57
58 for pair in query.split('&') {
59 if pair.is_empty() {
60 continue;
61 }
62 let (key, raw_value) = match pair.split_once('=') {
63 Some((k, v)) => (k, v),
64 None => (pair, ""),
65 };
66
67 let key = url_decode(key);
68 let raw_value = url_decode(raw_value);
69
70 map.insert(key, coerce_value(&raw_value));
71 }
72
73 map
74}
75
76pub fn query_string_to_json(query: &str) -> serde_json::Value {
80 serde_json::Value::Object(parse_query_string(query))
81}
82
83pub fn cookies_to_json(cookie_header: &str) -> serde_json::Value {
87 let mut map = serde_json::Map::new();
88
89 if cookie_header.is_empty() {
90 return serde_json::Value::Object(map);
91 }
92
93 for cookie in cookie_header.split(';') {
94 let cookie = cookie.trim();
95 if cookie.is_empty() {
96 continue;
97 }
98 let (name, value) = match cookie.split_once('=') {
99 Some((n, v)) => (n.trim(), v.trim()),
100 None => (cookie.trim(), ""),
101 };
102 map.insert(name.to_string(), coerce_value(value));
103 }
104
105 serde_json::Value::Object(map)
106}
107
108use serde::Serialize;
113
114vld::schema! {
115 #[derive(Debug, Clone, Serialize)]
120 pub struct ErrorBody {
121 pub error: String => vld::string(),
122 }
123}
124
125vld::schema! {
126 #[derive(Debug, Clone, Serialize)]
130 pub struct ErrorWithMessage {
131 pub error: String => vld::string(),
132 pub message: String => vld::string(),
133 }
134}
135
136vld::schema! {
137 #[derive(Debug, Clone, Serialize)]
139 pub struct ValidationIssue {
140 pub path: String => vld::string(),
141 pub message: String => vld::string(),
142 }
143}
144
145vld::schema! {
146 #[derive(Debug, Clone, Serialize)]
149 pub struct ValidationIssueWithCode {
150 pub path: String => vld::string(),
151 pub message: String => vld::string(),
152 pub code: String => vld::string(),
153 }
154}
155
156vld::schema! {
157 #[derive(Debug, Clone, Serialize)]
160 pub struct ValidationErrorBody {
161 pub error: String => vld::string(),
162 pub issues: Vec<ValidationIssue> => vld::array(vld::nested(ValidationIssue::parse_value)),
163 }
164}
165
166pub fn format_issues(err: &vld::error::VldError) -> Vec<ValidationIssue> {
173 err.issues
174 .iter()
175 .map(|i| {
176 let path: String = i
177 .path
178 .iter()
179 .map(|p| p.to_string())
180 .collect::<Vec<_>>()
181 .join(".");
182 ValidationIssue {
183 path,
184 message: i.message.clone(),
185 }
186 })
187 .collect()
188}
189
190pub fn format_vld_error(err: &vld::error::VldError) -> serde_json::Value {
195 let body = ValidationErrorBody {
196 error: "Validation failed".into(),
197 issues: format_issues(err),
198 };
199 serde_json::to_value(body).expect("ValidationErrorBody serialization cannot fail")
200}
201
202pub fn format_issues_with_code(err: &vld::error::VldError) -> Vec<ValidationIssueWithCode> {
207 err.issues
208 .iter()
209 .map(|issue| {
210 let path: String = issue
211 .path
212 .iter()
213 .map(|p| p.to_string())
214 .collect::<Vec<_>>()
215 .join("");
216 ValidationIssueWithCode {
217 path,
218 message: issue.message.clone(),
219 code: issue.code.key().to_string(),
220 }
221 })
222 .collect()
223}
224
225pub fn url_decode(input: &str) -> String {
229 let s = input.replace('+', " ");
230 let mut result = String::with_capacity(s.len());
231 let mut chars = s.chars();
232 while let Some(c) = chars.next() {
233 if c == '%' {
234 let hex: String = chars.by_ref().take(2).collect();
235 if let Ok(byte) = u8::from_str_radix(&hex, 16) {
236 result.push(byte as char);
237 } else {
238 result.push('%');
239 result.push_str(&hex);
240 }
241 } else {
242 result.push(c);
243 }
244 }
245 result
246}
247
248pub fn format_json_parse_error(message: &str) -> serde_json::Value {
258 serde_json::to_value(ErrorWithMessage {
259 error: "Invalid JSON".into(),
260 message: message.into(),
261 })
262 .expect("ErrorWithMessage serialization cannot fail")
263}
264
265pub fn format_utf8_error() -> serde_json::Value {
271 serde_json::to_value(ErrorBody {
272 error: "Invalid UTF-8".into(),
273 })
274 .expect("ErrorBody serialization cannot fail")
275}
276
277pub fn format_payload_too_large() -> serde_json::Value {
283 serde_json::to_value(ErrorBody {
284 error: "Payload too large".into(),
285 })
286 .expect("ErrorBody serialization cannot fail")
287}
288
289pub fn format_generic_error(error: &str) -> serde_json::Value {
295 serde_json::to_value(ErrorBody {
296 error: error.into(),
297 })
298 .expect("ErrorBody serialization cannot fail")
299}
300
301pub fn extract_path_param_names(pattern: &str) -> Vec<String> {
303 let mut names = Vec::new();
304 let mut chars = pattern.chars().peekable();
305 while let Some(c) = chars.next() {
306 if c == '{' {
307 let name: String = chars.by_ref().take_while(|&c| c != '}').collect();
308 if !name.is_empty() {
309 names.push(name);
310 }
311 }
312 }
313 names
314}