Drew
July 29, 2022, 6:17pm
1
A request responds with a body similar to the following
{
"status":"GOOD",
"fruits":[
{
"name":"Apple",
"details": {
"size":500
}
},
{
"name":"Cherry",
"details": {
"size":100
}
}]
}
I want to apply a JmesPath that contains a filter so that I only get back the first Fruit Object with size >= 500
The JmesPath I came up with is fruits[?details.size >= '500']|[0]
This path works correctly on the JmesPath site. However, it does not work in gatling. Gatling says it could not find an object with that JmesPath, specifically ...find.transform.exists, found nothing
My check in my request
.check(
jmesPath("fruits[?details.size >= '500']|[0]")
.ofMap()
.saveAs("fruitObj")
)
I can get a list all fruits with the path "fruits"
and the corresponding check of ofList()
I can get a JSON object if I use "fruits[0]"
and the check ofMap()
.
I can not get a list of fruits if I use the following
fruits[?details.size >= '1']
with ofList()
Am I using JmesPath incorrectly?
GeMi
July 29, 2022, 7:12pm
2
I have make a test of your problem
I created mocked service by Wiremock:
{
"request": {
"method": "GET",
"url": "/api/hmmm"
},
"response": {
"headers": {
"Content-Type": "application/json"
},
"status": 200,
"body": "{\"status\":\"GOOD\",\"fruits\":[{\"name\":\"Apple\",\"details\":{\"size\":500}},{\"name\":\"Cherry\",\"details\":{\"size\":100}}]}"
}
}
and created Simple Simulation:
import io.gatling.javaapi.core.ScenarioBuilder;
import io.gatling.javaapi.core.Simulation;
import io.gatling.javaapi.http.HttpProtocolBuilder;
import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.http;
public class JmeshPathSimulation extends Simulation {
HttpProtocolBuilder httpProtocol =
http
.baseUrl("http://127.0.0.1:8080");
ScenarioBuilder scn =
scenario("Scenario Name")
.exec(
http("request_1")
.get("/api/hmmm")
.check(
jmesPath("fruits[?details.size >= `500`]").ofList()
.saveAs("fruitObj")
)
).exec(session -> {
System.out.println(session.get("fruitObj").toString());
return session;
});
{
setUp(scn.injectOpen(atOnceUsers(1)).protocols(httpProtocol));
}
}
and everything is working
I think that you have '500' but you must have `500` when you using for filtering numbers.
1 Like
Drew
July 29, 2022, 7:31pm
3
You were absolutely correct. It has to be back ticked, so `500` not ‘500’.
For some reason the JmesPath site does not differentiate between the two if you use their sandbox space. The specification does list the difference.
literal = ` json-value`
Tip: I tend to use https://postman-echo.com to test this, so I don’t have to set up anything such as Wiremock.
1 Like
GeMi
July 30, 2022, 9:36pm
5
Nice tip.
Sometimes (at work all times;)) I like to have everything locally and using Wiremock (standalone jar) is good choise.
Just for the record: accepting '
(simple quote) for wrapping literals is not correct according to the JMESPath specification .
literal = "`" json-value "`"
IMHO, the implementation used on the website accepting simple quotes is a bug. I will try to report it.
GeMi
July 31, 2022, 8:27am
7
You have a little bug in post:
should be:
literal = "`" json-value "`"
Looking at Documentation I do not agree with you, such writing of literals is correct for Strings or I don’t understand correctly Documentation.
https://jmespath.org/specification.html#raw-string-literals
This is indeed a bug in the JavaScript JMESPath implementation (discussed on the JMESPath official chat) that’s used for the online evaluator.
I’ve opened a ticket there: Numeric literals can only wrapped with backticks, not single quotes · Issue #85 · jmespath/jmespath.js · GitHub
1 Like
GeMi
July 31, 2022, 8:12pm
10
Yeah, you are right - in the case shown in the issue (for numbers)
When I write about my disagree I meant that for numbers should be:
fruits[?details.size >= `500`]
but for Strings can be:
fruits[?name == `"Apple"`]
fruits[?name == 'Apple']