featherbit/vars/
jsonpath.rs1use serde_json_path::JsonPath;
7
8#[derive(Debug)]
10pub enum BodyTarget {
11 Request,
12 Response,
13}
14
15#[derive(Debug)]
17pub struct JsonSubject {
18 pub target: BodyTarget,
19 pub path: JsonPath,
20 #[allow(dead_code)]
24 pub raw: String,
25}
26
27pub fn parse_json_subject(subject: &str) -> Option<Result<JsonSubject, String>> {
31 let (target, path_str) = if let Some(p) = subject.strip_prefix("request_body:") {
32 (BodyTarget::Request, p)
33 } else if let Some(p) = subject.strip_prefix("response_body:") {
34 (BodyTarget::Response, p)
35 } else if subject.starts_with('$') {
36 (BodyTarget::Request, subject)
37 } else {
38 return None;
39 };
40 Some(
41 JsonPath::parse(path_str)
42 .map(|path| JsonSubject {
43 target,
44 path,
45 raw: subject.to_string(),
46 })
47 .map_err(|e| format!("invalid JSONPath '{}': {}", subject, e)),
48 )
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn test_jsonpath_subject_detection() {
57 assert!(parse_json_subject("http_authorization").is_none());
58 assert!(parse_json_subject("arg_name").is_none());
59 assert!(matches!(
60 parse_json_subject("$.user.name"),
61 Some(Ok(JsonSubject {
62 target: BodyTarget::Request,
63 ..
64 }))
65 ));
66 assert!(matches!(
67 parse_json_subject("request_body:$.a"),
68 Some(Ok(JsonSubject {
69 target: BodyTarget::Request,
70 ..
71 }))
72 ));
73 assert!(matches!(
74 parse_json_subject("response_body:$.a[*].b"),
75 Some(Ok(JsonSubject {
76 target: BodyTarget::Response,
77 ..
78 }))
79 ));
80 assert!(matches!(parse_json_subject("$.["), Some(Err(_))));
82 assert!(matches!(
83 parse_json_subject("response_body:nope"),
84 Some(Err(_))
85 ));
86 }
87}