Validating Nested JSON
A Nested JSON response contains JSON objects inside other JSON objects or arrays.
Most real-world REST APIs return nested JSON structures, so API automation must validate values located deep inside the response.
REST Assured uses JsonPath with dot notation to navigate nested objects.
Interview Answer
"Nested JSON validation means verifying values that are present inside child objects or arrays. In REST Assured, I use JsonPath expressions such as
user.address.cityorusers[0].role.nametogether withbody()assertions to validate nested values."
Nested JSON Example
{
"user": {
"id": 101,
"name": "John",
"address": {
"city": "Hyderabad",
"pincode": 500001
}
}
}
JSON Structure
user
│
├── id
├── name
└── address
│
├── city
└── pincode
Validate Nested Fields
given()
.when()
.get("/users/101")
.then()
.statusCode(200)
.body("user.address.city", equalTo("Hyderabad"))
.body("user.address.pincode", equalTo(500001));
Nested Array Example
{
"users":[
{
"id":101,
"name":"John"
},
{
"id":102,
"name":"David"
}
]
}
Validate Nested Array
.body("users[0].name", equalTo("John"))
.body("users[1].id", equalTo(102));
Real-Time Example
In my project, we validated nested fields such as city, pincode, and role name, which were present inside multiple levels of nested JSON objects returned by the API.
Best Practices
- Use dot notation for nested objects.
- Use array indexes for array elements.
- Combine nested validation with status code validation.
- Validate mandatory nested fields using
notNullValue().
Validating Array Responses
Many APIs return arrays instead of a single object.
Array validation ensures:
- Correct number of elements
- Expected values exist
- Correct values at specific indexes
Sample Array Response
{
"users": [
{
"id": 101,
"name": "John"
},
{
"id": 102,
"name": "David"
},
{
"id": 103,
"name": "Rahul"
}
]
}
Validate Array Size
.body("users", hasSize(3));
Validate Value at Index
.body("users[0].name", equalTo("John"));
Validate Existing Value
.body("users.name", hasItem("David"));
Validate Multiple Values
.body("users.name",
hasItems("John", "Rahul"));
Array Validation Flow
Array Response
│
▼
Validate Size
│
▼
Validate Index
│
▼
Validate Expected Values
Real-Time Example
In our automation framework, we validated the total number of users returned by the API, verified IDs at specific indexes, and confirmed that expected roles existed in the response array.
Best Practices
- Validate array size.
- Validate important indexes.
- Validate expected values using
hasItem(). - Avoid relying on indexes when the order is not guaranteed.
Validating Dynamic Values
Some API values change every time the API is executed.
Examples:
- User ID
- Order ID
- JWT Token
- Timestamp
- UUID
These values should not be validated using fixed values.
Common Dynamic Matchers
| Matcher | Purpose |
|---|---|
notNullValue() |
Value exists |
greaterThan() |
Numeric comparison |
lessThan() |
Numeric comparison |
matchesRegex() |
Pattern validation |
Validate Dynamic ID
.body("id",
greaterThan(0));
Validate Token
.body("token",
notNullValue());
Validate Timestamp
.body("createdAt",
notNullValue());
Validate Using Regex
.body("email",
matchesRegex(".+@.+\\..+"));
Extract and Validate
int id =
response.jsonPath()
.getInt("id");
Assert.assertTrue(id > 0);
Real-Time Example
In my project, Order IDs and timestamps were generated dynamically. Instead of comparing fixed values, we validated that the Order ID was greater than zero and that the timestamp was present using
notNullValue().
Best Practices
- Never hardcode dynamic values.
- Use matchers such as
notNullValue()andgreaterThan(). - Extract values when additional custom validation is required.
Handling Null Values
Some API fields are optional and may legitimately return null.
REST Assured provides matchers to validate whether fields are null or not.
Validate Null Value
.body("middleName",
nullValue());
Validate Mandatory Field
.body("email",
notNullValue());
Null Validation Table
| Scenario | Matcher |
|---|---|
| Optional Field | nullValue() |
| Mandatory Field | notNullValue() |
Real-Time Example
We validated optional fields such as
middleNameusingnullValue()and mandatory fields such asuserIdandnotNullValue(). Unexpected null values were treated as defects.
Best Practices
- Clearly identify optional fields.
- Validate mandatory fields using
notNullValue(). - Log defects when mandatory values are unexpectedly null.
Asserting Response Headers
Response headers provide metadata about the API response.
REST Assured allows validation of both individual headers and multiple headers.
Common Response Headers
- Content-Type
- Cache-Control
- Content-Encoding
- Server
- Date
- Custom Security Headers
Validate Single Header
response.then()
.header("Content-Type",
"application/json");
Validate Multiple Headers
response.then()
.headers(
"Content-Type",
"application/json",
"Cache-Control",
"no-cache"
);
Real-Time Example
In my project, every API was validated to ensure it returned
application/jsonas theContent-Type. We also verified security-related headers such asCache-Controland reported missing headers as defects.
Best Practices
- Validate
Content-Type. - Validate security headers.
- Validate caching headers when applicable.
- Verify custom headers for business requirements.
Asserting Cookies
Some applications use cookies to maintain user sessions.
REST Assured allows validation of cookies returned by the API.
Validate Cookie
response.then()
.cookie("JSESSIONID");
Validate Cookie Value
response.then()
.cookie("USER", "John");
Cookie Validation Flow
API Response
│
▼
Cookie Returned?
│
▼
Validate Cookie
│
▼
Validate Cookie Value
Real-Time Example
During session-based authentication testing, we verified that the server returned the expected session cookie and that its value matched the authenticated user session.
Extracting a Value and Chaining Requests
Real-world API workflows often depend on values returned by previous API calls.
Examples:
- Login → Token
- Create User → User ID
- Create Order → Order ID
These values are extracted and reused in subsequent requests.
Chaining Flow
Login API
│
▼
Extract Token
│
▼
Create User API
│
▼
Extract User ID
│
▼
Update User API
│
▼
Get User API
Extract Token
String token =
response.jsonPath()
.getString("token");
Pass Token
given()
.header("Authorization",
"Bearer " + token)
Extract ID
int id =
response.jsonPath()
.getInt("id");
Pass Path Parameter
given()
.pathParam("id", id)
.when()
.get("/users/{id}");
Real-Time Example
In our framework, the Login API generated a JWT token, which we extracted using JsonPath and reused in the
Authorizationheader. Similarly, after creating a user, we extracted the generated User ID and passed it as a path parameter to the Update User and Get User APIs, enabling complete end-to-end API automation.
Best Practices
- Extract dynamic values immediately after receiving the response.
- Reuse extracted values instead of hardcoding them.
- Validate extracted values before using them in subsequent requests.
- Use JsonPath expressions that clearly reflect the response structure.
- Combine extraction with response validation to ensure data correctness.
Frequently Asked Questions (FAQs)
1. How do you validate nested JSON?
I use JsonPath dot notation such as user.address.city or users[0].role.name inside body() assertions to navigate and validate nested JSON values.
2. How do you validate an array response?
I validate:
- Array size using
hasSize() - Values at specific indexes such as
users[0].name - Presence of expected values using
hasItem()orhasItems()
This ensures both the structure and content of the array are correct.
3. How do you validate dynamic values like IDs and timestamps?
Since these values change for every execution, I avoid comparing fixed values. Instead, I use matchers such as:
notNullValue()greaterThan()matchesRegex()
or extract the values using JsonPath and perform conditional validations.
4. How do you handle null values in a response?
I validate optional fields using nullValue() and mandatory fields using notNullValue(). If a mandatory field unexpectedly returns null, the test fails and the issue is reported as a defect.
5. How do you assert response headers?
I use:
header()to validate a single response headerheaders()to validate multiple headers
Common validations include Content-Type, Cache-Control, Content-Encoding, and other security-related headers.
6. How do you chain requests?
I extract dynamic values such as tokens or IDs using JsonPath, for example:
response.jsonPath().getString("token")
or
response.jsonPath().getInt("id")
Then I reuse those values in subsequent requests as:
- Authorization headers
- Path parameters
- Query parameters
- Request body values
This approach enables complete end-to-end API workflow automation.