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.

Advertisement

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.city or users[0].role.name together with body() 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() and greaterThan().
  • 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 middleName using nullValue() and mandatory fields such as userId and email using notNullValue(). 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/json as the Content-Type. We also verified security-related headers such as Cache-Control and 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.


 
response.then()
        .cookie("JSESSIONID");
 

 
response.then()
        .cookie("USER", "John");
 

 
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 Authorization header. 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() or hasItems()

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 header
  • headers() 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.