From a36a9d6f7eecd1be1dab80ce80c3b2e30ac44f43 Mon Sep 17 00:00:00 2001 From: Lucas Pickering Date: Wed, 25 Oct 2023 07:23:12 -0400 Subject: [PATCH] Pre-parse JSONPath in collection --- src/config/mod.rs | 4 ++-- src/template.rs | 37 ++++++------------------------------- 2 files changed, 8 insertions(+), 33 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 167104ea..f234d8e1 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -5,6 +5,7 @@ use anyhow::{anyhow, Context}; use derive_more::{Deref, Display, From}; use indexmap::IndexMap; use serde::{Deserialize, Serialize}; +use serde_json_path::JsonPath; use std::{ future::Future, path::{Path, PathBuf}, @@ -106,8 +107,7 @@ pub struct Chain { #[serde(default)] pub sensitive: bool, /// JSONpath to extract a value from the response. For JSON data only. - // TODO strong typing on this - pub selector: Option, + pub selector: Option, } /// The source of data for a chain diff --git a/src/template.rs b/src/template.rs index 76a631ce..c432b41d 100644 --- a/src/template.rs +++ b/src/template.rs @@ -356,15 +356,8 @@ impl<'a> ChainTemplateSource<'a> { fn apply_selector( &self, value: Cow<'_, str>, - selector: &'a str, + selector: &JsonPath, ) -> Result, ChainError> { - // Parse the JSON path - let path = - JsonPath::parse(selector).map_err(|err| ChainError::JsonPath { - selector: selector.to_owned(), - error: err, - })?; - // Parse the response as JSON. Intentionally ignore the // content-type. If the user wants to treat it as JSON, we // should allow that even if the server is wrong. @@ -372,7 +365,7 @@ impl<'a> ChainTemplateSource<'a> { .map_err(|err| ChainError::ParseResponse { error: err })?; // Apply the path to the json - let found_value = path + let found_value = selector .query(&json_value) .exactly_one() .map_err(|err| ChainError::InvalidResult { error: err })?; @@ -451,12 +444,6 @@ pub enum ChainError { /// response #[error("No response available")] NoResponse, - #[error("Error parsing JSON path {selector:?}")] - JsonPath { - selector: String, - #[source] - error: serde_json_path::ParseError, - }, /// Failed to parse the response body before applying a selector #[error("Error parsing response")] ParseResponse { @@ -561,11 +548,12 @@ mod tests { ) .await .unwrap(); + let selector = selector.map(|s| s.parse().unwrap()); let chains = vec![create!( Chain, id: "chain1".into(), source: ChainSource::Request(recipe_id), - selector: selector.map(String::from), + selector: selector, )]; let context = create!( TemplateContext, repository: repository, chains: chains, @@ -591,20 +579,7 @@ mod tests { Chain, id: "chain1".into(), source: ChainSource::Request("recipe1".into()), - selector: Some("$.".into()), - ), - Some(( - create!(Request, recipe_id: "recipe1".into()), - create!(Response, body: "{}".into()), - )), - "Error parsing JSON path \"$.\"", - )] - #[case( - create!( - Chain, - id: "chain1".into(), - source: ChainSource::Request("recipe1".into()), - selector: Some("$.message".into()), + selector: Some("$.message".parse().unwrap()), ), Some(( create!(Request, recipe_id: "recipe1".into()), @@ -617,7 +592,7 @@ mod tests { Chain, id: "chain1".into(), source: ChainSource::Request("recipe1".into()), - selector: Some("$.*".into()), + selector: Some("$.*".parse().unwrap()), ), Some(( create!(Request, recipe_id: "recipe1".into()),