hurl icon indicating copy to clipboard operation
hurl copied to clipboard

Assert against every member of a JSONPATH collection?

Open danielbprice opened this issue 4 years ago • 3 comments

Hi, I'm sorry if this is an ignorant question. Let's imagine an API which returns an array of elements:

{
  "data": [
    { "item": "value1" },
    { "item": "value2" },
    { "item": "value3" }
  ]
}

My basic use case is that I want to assert that all of the values of "item" match the pattern "value.*". Today it seems like I can do:

jsonpath "$.data[0].item" matches "value.*"

However I would really like a way to say:

jsonpath "$.data[*].item" matches "value.*"

That is to say, test each member against the regex. What seems to happen when I try this is that all of the items are concatenated, so that the match is against something like [string <value1>, string <value2>, string <value3>] (according to the output of hurl). I can see using https://jsonpath.com/ that this is due to the way jsonpath processes the input.

I tried to bend jsonpath to emit a collection of elements whose value does not match value.* (so I could assert that zero things remained) but couldn't figure it out.

Something I wondered along the way is whether it would make sense to be able to run the predicate on each value in a resultant collection. So jsonpath "$.data[*].item" EACH matches "value.*"

Thanks for your consideration! I have had good success using hurl to help me build an API gateway.

danielbprice avatar Nov 08 '21 20:11 danielbprice

Your understanding of Hurl is good. That's also how we would do it.

In a testing/controlled environment, responses can be tested "statically" as you suggested.

jsonpath "$.data[*].item" count == 3
jsonpath "$.data[0].item" matches "value.*"
jsonpath "$.data[1].item" matches "value.*"
jsonpath "$.data[2].item" matches "value.*"

I like your "each" operator for a list. it would become very useful is the collection is very large and could be combined very nicely with the existing predicates.

jsonpath "$.values" each == 3
jsonpath "$.values" each > 0 
jsonpath "$.values" each matches "value.*"

fabricereix avatar Nov 09 '21 07:11 fabricereix

Very good idea, we could also support any or none.

jsonpath "$.values" any == 3
jsonpath "$.values" any > 0 
jsonpath "$.values" any matches "value.*"
jsonpath "$.values" none == 3
jsonpath "$.values" none > 0 
jsonpath "$.values" none matches "value.*"

A sidenote: in Hurl syntax, we have the notion of query and predicate. Ex:

jsonpath "$.data[0].item" matches "value.*"

query: jsonpath "$.data[0].item" predicate: matches predicate-value: "value.*"

If we negate:

jsonpath "$.data[0].item" not matches "value.*"

(not if part of predicate)

Using each:

jsonpath "$.values" each not matches "value.*"
jsonpath "$.values" each != "something"

each belongs definitively to the predicate https://hurl.dev/docs/asserting-response.html#predicates. It a kind of predicate iterator.

@danielbprice Thanks for the idea; is your project using Hurl Open Source so we can look at it? I'm really interested to see how other people use Hurl!

jcamiel avatar Nov 09 '21 09:11 jcamiel

@jcamiel unfortunately it's not a piece of open source that I can share. It's an API gateway to support a single enterprise customer, mapping an older version of an API to a newer version in a situation where that was really the only option.

Also "none" and "any" seem smart. Thanks for listening.

danielbprice avatar Nov 12 '21 00:11 danielbprice