Skip to content

Commit

Permalink
Pre-parse JSONPath in collection
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasPickering committed Oct 25, 2023
1 parent 1929bb0 commit ea79742
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 34 deletions.
2 changes: 1 addition & 1 deletion docs/src/user_guide/templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Templates enable dynamic string construction. Slumber's template language is relatively simple, compared to complex HTML templating languages like Handlebars or Jinja. The goal is to be intuitive and unsurprising. It doesn't support complex features like for loops, conditionals, etc.

All string _values_ (i.e. _not_ keys) in a request collection are template strings, meaning they support templating. The syntax for templating a value into a string is double curly braces (`{{...}}`). The contents inside the braces tell Slumber how to retrieve the dynamic value.
All string _values_ (i.e. _not_ keys) in a request collection are template strings, meaning they support templating. The syntax for templating a value into a string is double curly braces `{{...}}`. The contents inside the braces tell Slumber how to retrieve the dynamic value.

TODO add some more content here

Expand Down
4 changes: 2 additions & 2 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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<String>,
pub selector: Option<JsonPath>,
}

/// The source of data for a chain
Expand Down
37 changes: 6 additions & 31 deletions src/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,23 +356,16 @@ impl<'a> ChainTemplateSource<'a> {
fn apply_selector(
&self,
value: Cow<'_, str>,
selector: &'a str,
selector: &JsonPath,
) -> Result<Cow<'a, str>, 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.
let json_value = Json::parse(&value)
.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 })?;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand All @@ -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()),
Expand All @@ -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()),
Expand Down

0 comments on commit ea79742

Please sign in to comment.