Selecting response elements with GPath in REST Assured

Hey, another post on REST Assured! This time I’d like to take a closer look at how you can select elements from a JSON or XML response to check their values. For this, REST Assured uses GPath, a path expression language integrated into the Groovy language. It is similar to XPath for XML, but GPath can handle both XML and JSON. This makes it an excellent fit for checking responses of RESTful web services. Read more on GPath here or here.

To see how GPath works and how you can use it effectively in REST Assured tests, let’s consider the following JSON response from the Ergast MRD API. This response lists all drivers for the 2016 Formula 1 season:

JSON response containing all Formula 1 drivers for the 2016 season

You can see the full response by selecting (or otherwise performing a GET call to) this link.

Extracting a single element value
Say we want to extract the driverId of the last driver and check that it is equal to wehrlein. Like with XPath, you can simply specify the path to the element starting with the root node and navigating through the tree until the required node is reached. Note that the index [-1] is used by GPath to denote the last matching element.

@Test
public void extractAndCheckSingleValue() {
		
	given().
	when().
		get("http://ergast.com/api/f1/2016/drivers.json").
	then().
		assertThat().
		body("MRData.DriverTable.Drivers.driverId[-1]",equalTo("wehrlein"));
}

Extracting a set of element values
Another check we might want to perform is that the collection of driverId values contains some specific values. This is done using a GPath expression very similar to the previous example:

@Test
public void extractAndCheckMultipleValues() {
		
	given().
	when().
		get("http://ergast.com/api/f1/2016/drivers.json").
	then().
		assertThat().
		body("MRData.DriverTable.Drivers.driverId",hasItems("alonso","button"));
}

Using the REST Assured base path
By now, you might have noticed that in every GPath expression we needed to start navigating from the root node MRData downwards. This results in quite long GPath expressions. REST Assured has a nifty little feature that can simplify these expressions by having you define a BasePath:

@BeforeTest
public void initPath() {
		
	RestAssured.rootPath = "MRData.DriverTable.Drivers";
}

This cleans up our tests and has a positive effect on maintainability:

@Test
public void extractAndCheckMultipleValues() {
		
	given().
	when().
		get("http://ergast.com/api/f1/2016/drivers.json").
	then().
		assertThat().
		body("driverId",hasItems("alonso","button"));
}

Extracting a specific subset of values
GPath also supports array slicing to retrieve specific subsets of a collection of values. In the example below, we check that the collection of elements with index [0] through [2] has exactly three items (the ones at index [0], [1] and [2]):

@Test
public void extractAndCheckArraySliceSize() {
		
	given().
	when().
		get("http://ergast.com/api/f1/2016/drivers.json").
	then().
		assertThat().
		body("driverId[0..2]",hasSize(3));
}

Filtering values
Using GPath, you can also filter values to return an even more specific subset of values. For example, if we only want to return the collection of permanentNumber values in use this year that are between 20 and 30 inclusive, we can do this:

@Test
public void extractAndCheckRange() {
		
	given().
	when().
		get("http://ergast.com/api/f1/2016/drivers.json").
	then().
		assertThat().
		body("findAll{Drivers->Drivers.permanentNumber >= \"20\" && Drivers.permanentNumber <= \"30\"}.permanentNumber",hasItem("22")).
		and().
		body("findAll{Drivers->Drivers.permanentNumber >= \"20\" && Drivers.permanentNumber <= \"30\"}.permanentNumber",not(hasItem("33")));
}

The quotes around the lower and upper boundary are required since the API call returns the permanentNumber values as strings instead of integers.

Use parameters
To make the previous example a little more flexible, we can parameterize both the lower and upper boundaries as well as the values that are expected to be (or not to be) in the resulting collection. Let’s specify these in a TestNG DataProvider first:

@DataProvider(name = "rangesAndValues")
public String[][] createTestDataObject() {
		
	return new String[][] {
		{"20","30","22","25"},
		{"30","40","33","31"},
		{"1","9","9","4"}
	};
}

Now we can apply these in our test:

@Test(dataProvider = "rangesAndValues")
public void extractAndCheckRangeParameterized(String lowerLimit, String upperLimit, String inCollection, String notInCollection) {
		
	given().
	when().
		get(getDriverListFor2016).
	then().		
		assertThat().
		body("findAll{Drivers->Drivers.permanentNumber >= \"" + lowerLimit + "\" && Drivers.permanentNumber <= \"" + upperLimit + "\"}.permanentNumber",hasItem(inCollection)).
		and().
		body("findAll{Drivers->Drivers.permanentNumber >= \"" + lowerLimit + "\" && Drivers.permanentNumber <= \"" + upperLimit + "\"}.permanentNumber",not(hasItem(notInCollection)));
}

Note that the syntax gets a little messy here, especially since we have to keep the escaped double quotes in the GPath expression. There might be an easier way to do this, but I haven’t found one that still supports the given()/when()/then() format. Any pointers on this are well appreciated!

Sample code
You can download a Maven project containing all the code examples presented in this blog post here.

27 thoughts on “Selecting response elements with GPath in REST Assured

  1. Pingback: Java Web Weekly, Issue 127 | Baeldung

  2. Sorry for the double post but my code examples didn’t get rendered correctly. I’m trying with gists instead.

    Hi,

    Nice blog post. Just wanted to mention that you can also use single quotes in GPath expressions to make them more readable. And you can also use “withArgs” if you like. For example:

    https://gist.github.com/johanhaleby/6c1b9dd511e867ff1d9d7edde938d0d5

    But as you can see the path is duplicated, so you could specify a root path:

    https://gist.github.com/johanhaleby/31d272d7c7062a1604abbb2ac3ac0396

    But in this particular case (since the args are also duplicated) an alternative would be to use compose the Hamcrest matchers:

    https://gist.github.com/johanhaleby/4006723df703272b05208974d030c7b1

    But I suppose it’s a matter of taste.

  3. Hey Johan,

    thanks a lot for those suggestions! I wasn’t aware of the possibility to use withArgs in GPath, not did I see composite Hamcrest matchers before, so you’ve managed to teach at least one person something new. Will definitely use those (where applicable of course) in future posts and REST Assured projects / workshops / …

    I took the liberty of trashing your first comment as it was indeed rather unreadable..

  4. Pingback: Testing Bits – 5/29/16 – 6/4/16 | Testing Curator Blog

    • Whoops.. Completely forgot to upload the project! Will do so later tonight. Thanks for pointing this out to me!

      EDIT: Fixed!

  5. Hello 🙂 Great article. I have some question . How I can get driver json from array if in json will not have attribute “Drivers”. Also i want to filtr this driver json object.

  6. Hi Bas,
    Thanks for the article.

    FYI: I just downloaded the code and one of the tests is now failing. Not sure if the data changed since you wrote the test…
    FAILED: extractAndCheckRangeParameterized(“30”, “40”, “33”, “31”)
    java.lang.AssertionError: 1 expectation failed.
    JSON path MRData.DriverTable.Drivers.findAll{Drivers->Drivers.permanentNumber >= “30” && Drivers.permanentNumber <= "40"}.permanentNumber doesn't match.
    Expected: not a collection containing "31"
    Actual: [31, 30, 33]

    Tim

  7. Hi Bas,

    Can you please suggest some resources for learning API test automation using SOAPUI.

    For learning API (receiving JSON responses) test automation, should I go for SOAPUI or REST Assured.

    Thanks
    Rajat

    • Rajat,
      I am also trying to learn these tools for automated REST testing.

      You may want to look at POSTMAN, it may not be the tool you use to do your actual automation, but for me it is a great tool for learning REST and JSON. This was a great video: youtube: POSTMAN RESTful API testing app demo. You can use this in combination with Newman and run automated tests via Jenkins.

      In addition to this I also setup Fiddler. This is a packet sniffer similar to Charles and Wireshark. It works on Windows and Linux, not sure about Mac (probably). This is nice because you can see what is being sent and received via your REST communication. Not sure if Bas has any articles on Fiddler, if not it would be great to see one (hint, hint)

      I’m also using TestNG with Rest-Assured, looks like a great tool. However, I’m getting a bit hung up with GPATH and non-friendly json (my term). It would be nice if there was a Rest-Assured-GPATH test site.

      I have used SoapUI for testing Soap msgs but not REST. I have used the Groovy capabilities within SoapUI, it could be a good fit for REST as GPATH is a groovy lib.

      It never hurts to have a bunch of tools in your tool box

      Tim

      PS – this is a great site for test automation, keep up the good work Bas!

  8. Hi, Your blog topics are very much relevant to a newbie as well as a experienced tester. I keep referring to your blogs to find answers to my questions. I also try to follow why, what, how approach. After you introduced RESTASSURED my life has become so much easy. Earlier I was using Apahce HttpComponents.

  9. Hello, Bas
    Thank you, very usefull topics in your blog!
    Can you tell me, please, how to parse json response and put values to another response? Thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *