Introduction
In our REST Assured series, we’ve covered topics like Status Code Validation, Response Specification, and PATCH Requests, building a strong foundation for API testing. Now, we’ll explore JSON Path, a powerful feature in REST Assured for extracting and validating data from JSON responses. This guide demonstrates how to use JSON Path to navigate and test JSON structures, ensuring accurate API behavior. It’s designed for beginners and experienced developers, offering clear explanations and practical examples.
Key Point: JSON Path in REST Assured enables you to query and validate specific elements in JSON responses, simplifying complex data extraction and verification in API tests.
What is JSON Path?
JSON Path is a query language for JSON, similar to XPath for XML, allowing you to select and extract data from JSON structures using a concise syntax path. In REST Assured, JSON Path is integrated to parse JSON responses, enabling you to:
- Extract specific fields or nested values.
- Validate data using assertions.
- Handle arrays, objects, and complex JSON structures.
REST Assured’s JSON Path implementation is based on the Jayway JSONPath library, providing a robust way to navigate JSON responses. We’ll use the public API https://jsonplaceholder.typicode.com
, which returns structured JSON data, for our examples.
Setting Up for JSON Path Testing
To use JSON Path, we’ll set up a Maven project with REST Assured, JUnit, and Allure for reporting. The setup is consistent with previous posts in the series.
Here’s the pom.xml
, styled with the requested Blogger format for XML syntax highlighting:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>rest-assured</artifactId>
<version>1.0</version>
<properties>
<java.version>11</java.version>
<allure.version>2.27.0</allure.version>
<aspectj.version>1.9.22</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit5</artifactId>
<version>${allure.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-maven</artifactId>
<version>2.12.0</version>
<configuration>
<reportVersion>${allure.version}</reportVersion>
</configuration>
</plugin>
</plugins>
</build>
</project>
No additional setup is needed for https://jsonplaceholder.typicode.com
, as it provides rich JSON responses for JSON Path testing.
Using JSON Path in REST Assured
Let’s explore how to use JSON Path to extract and validate data from JSON responses in various scenarios.
Example 1: Basic JSON Path Extraction
Extract a single field from a JSON response using JSON Path and validate its value.
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
@Feature("JSON Path Testing")
public class BasicJsonPathTest {
@Test
@Description("Extract and validate a single field using JSON Path")
public void testExtractPostTitle() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.log().all()
.when()
.get("/posts/1")
.then()
.statusCode(200)
.body("title", notNullValue())
.body("title", isA(String.class));
}
}
Explanation:
body("title", notNullValue())
: Uses JSON Pathtitle
to validate thetitle
field is not null.isA(String.class)
: Ensures thetitle
is a string.- The JSON Path
title
directly accesses the top-leveltitle
field in the response.
Important: JSON Path expressions in REST Assured are intuitive, using dot notation (e.g.,userId
) or array indices (e.g.,posts[0]
) to navigate JSON structures.
Example 2: Navigating Nested JSON Structures
Use JSON Path to extract and validate nested fields in a complex JSON response.
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import io.restassured.path.json.JsonPath;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.junit.jupiter.api.Assertions.*;
@Feature("JSON Path Testing")
public class NestedJsonPathTest {
@Test
@Description("Extract and validate nested fields using JSON Path")
public void testExtractNestedFields() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
String response = given()
.log().all()
.when()
.get("/users/1")
.then()
.statusCode(200)
.extract().asString();
JsonPath jsonPath = new JsonPath(response);
String companyName = jsonPath.getString("company.name");
String city = jsonPath.getString("address.city");
assertEquals("Romaguera-Crona", companyName);
assertNotNull(city);
}
}
Explanation:
JsonPath jsonPath = new JsonPath(response)
: Creates a JsonPath object from the response string.getString("company.name")
: Extracts the nestedname
field undercompany
.getString("address.city")
: Extracts the nestedcity
field underaddress
.- Assertions verify the extracted values.
Sample Response Structure:
{
"id": 1,
"name": "Leanne Graham",
"address": {
"city": "Gwenborough",
"street": "Kulas Light"
},
"company": {
"name": "Romaguera-Crona"
}
}
Example 3: Handling JSON Arrays with JSON Path
Use JSON Path to extract and validate elements from JSON arrays.
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
@Feature("JSON Path Testing")
public class JsonArrayPathTest {
@Test
@Description("Validate elements in a JSON array using JSON Path")
public void testExtractArrayElements() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.log().all()
.when()
.get("/posts")
.then()
.statusCode(200)
.body("[0].id", equalTo(1))
.body("[0].title", notNullValue())
.body("size()", greaterThan(0));
}
}
Explanation:
[0].id
: Accesses theid
of the first post in the array.[0].title
: Validates thetitle
of the first post is not null.size()
: Checks the array length is greater than zero.
Sample Response Structure:
[
{
"id": 1,
"title": "sunt aut facere...",
"body": "quia et suscipit..."
},
{
"id": 2,
"title": "qui est esse...",
"body": "est rerum tempore..."
}
]
Pro Tip: Use JSON Path’s array notation (e.g.,[0]
,[*]
) to handle lists of objects efficiently.
Example 4: Combining JSON Path with Response Specification
Integrate JSON Path validations with a ResponseSpecification for reusable tests.
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.specification.ResponseSpecification;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
@Feature("JSON Path Testing")
public class JsonPathWithSpecTest {
private ResponseSpecification responseSpec;
@BeforeEach
public void setup() {
responseSpec = new ResponseSpecBuilder()
.expectStatusCode(200)
.expectContentType("application/json")
.expectBody("id", notNullValue())
.expectBody("title", notNullValue())
.build();
}
@Test
@Description("Validate JSON Path with Response Specification")
public void testJsonPathWithSpec() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.log().all()
.when()
.get("/posts/1")
.then()
.spec(responseSpec)
.body("userId", equalTo(1));
}
}
Explanation:
responseSpec
: Includes JSON Path validations forid
andtitle
.spec(responseSpec)
: Applies the specification to the test.- Additional JSON Path validation (
userId
) is test-specific.
Integrating with Allure Reporting
Document JSON Path tests with Allure, attaching extracted data and response details.
import io.qameta.allure.Allure;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import io.restassured.path.json.JsonPath;
import io.restassured.response.Response;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
@Feature("JSON Path Testing")
public class AllureJsonPathTest {
@Test
@Description("Validate JSON Path with Allure reporting")
public void testJsonPathWithAllure() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
Response response = given()
.log().all()
.when()
.get("/posts/1")
.then()
.statusCode(200)
.body("title", notNullValue())
.extract().response();
JsonPath jsonPath = response.jsonPath();
String title = jsonPath.getString("title");
Allure.addAttachment("Extracted Title", "text/plain", title, ".txt");
Allure.addAttachment("Response Body", "application/json", response.asString(), ".json");
}
}
Explanation:
response.jsonPath()
: Creates a JsonPath object from the response.Allure.addAttachment
: Attaches the extractedtitle
and full response body to the Allure report.- Run
mvn clean test
andmvn allure:serve
to view the report.
Integrating with CI/CD
Add JSON Path tests to a GitHub Actions pipeline for automated execution.
Create or update .github/workflows/ci.yml
:
name: REST Assured CI Pipeline
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'temurin'
- name: Cache Maven dependencies
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-maven-
- name: Run tests
run: mvn clean test
- name: Generate Allure report
run: mvn allure:report
- name: Upload Allure results
if: always()
uses: actions/upload-artifact@v4
with:
name: allure-results
path: target/allure-results
- name: Publish Allure report
if: always()
uses: simple-elf/allure-report-action@v1.7
with:
allure_results: target/allure-results
gh_pages: gh-pages
allure_report: allure-report
- name: Deploy report to GitHub Pages
if: always()
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: allure-report
Explanation:
- Runs JSON Path tests with
mvn clean test
. - Publishes Allure reports to GitHub Pages for visibility.
Tips for Beginners
- Learn JSON Path Syntax: Master dot notation (e.g.,
company.name
) and array access (e.g.,[0]
) for effective queries. - Inspect Responses: Log responses with
log().all()
to understand JSON structures before writing JSON Path expressions. - Use Assertions: Combine JSON Path with Hamcrest matchers for robust validations.
- Handle Complex JSON: Use
JsonPath
objects for advanced extractions in nested or array-heavy responses.
Troubleshooting Tip: If a JSON Path expression fails, verify the response structure using log().all()
and check the path syntax against the JSON hierarchy.
What’s Next?
This post enhances our REST Assured series by introducing JSON Path, a key tool for JSON response validation. To continue your learning, consider exploring:
- GraphQL Testing: Testing GraphQL APIs with REST Assured.
- Advanced Allure Reporting: Customizing reports with environments and categories.
- End-to-End Testing: Combining REST Assured with Selenium for UI and API testing.