JSON Schema Validation with REST Assured: Ensuring API Data Integrity
Introduction
In our REST Assured series, we’ve explored topics like File Uploads and File Downloads, Multi-Part Form Data, and Filters, building a robust foundation for API testing. Now, we’ll dive into JSON Schema Validation, a powerful technique to verify that API responses conform to expected JSON structures. This guide demonstrates how to use REST Assured to validate JSON responses against a schema, with practical examples and best practices. It’s designed for beginners and experienced developers, ensuring you can confidently test API data integrity.
Key Point: JSON Schema Validation in REST Assured ensures API responses match predefined data structures, enhancing test reliability and catching data contract violations early.
What is JSON Schema Validation?
JSON Schema is a specification for defining the structure and data types of JSON data. It allows you to specify properties, required fields, data types, and constraints (e.g., string length, number ranges). In API testing, JSON Schema Validation ensures that responses adhere to this schema, catching issues like missing fields, incorrect types, or invalid values.
REST Assured supports JSON Schema Validation through the io.rest-assured.module.jsv
module, using the matchesJsonSchemaInClasspath()
or matchesJsonSchema()
methods. We’ll use https://jsonplaceholder.typicode.com/posts
for examples, validating its JSON response against a schema stored in the project’s resources. The schema will define the structure of a post object, ensuring fields like id
, userId
, title
, and body
are present and correctly typed.
Setting Up for JSON Schema Validation
We’ll set up a Maven project with REST Assured, JUnit, and Allure for reporting, adding the rest-assured-json-schema-validator
dependency for schema validation. The JSON Schema will be stored in src/test/resources/schemas/post-schema.json
.
Here’s the updated pom.xml
, styled with your preferred Blogger format for XML syntax highlighting:
4.0.0
com.example
rest-assured-tests
1.0-SNAPSHOT
11
2.27.0
1.9.22
io.rest-assured
rest-assured
5.4.0
test
io.rest-assured
json-schema-validator
5.4.0
test
org.junit.jupiter
junit-jupiter
5.10.2
test
org.hamcrest
hamcrest
2.2
test
com.fasterxml.jackson.core
jackson-databind
2.15.2
test
io.qameta.allure
allure-junit5
${allure.version}
test
org.apache.maven.plugins
maven-surefire-plugin
3.2.5
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
org.aspectj
aspectjweaver
${aspectj.version}
io.qameta.allure
allure-maven
2.12.0
${allure.version}
Create a JSON Schema file at src/test/resources/schemas/post-schema.json
:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"id": { "type": "integer" },
"userId": { "type": "integer" },
"title": { "type": "string" },
"body": { "type": "string" }
},
"required": ["id", "userId", "title", "body"],
"additionalProperties": false
}
This schema defines a post object with required fields and their types, matching the structure of https://jsonplaceholder.typicode.com/posts
responses.
Performing JSON Schema Validation
Let’s explore how to validate JSON responses against a schema using REST Assured.
Example 1: Basic JSON Schema Validation
Validate a single post response against the schema.
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 io.restassured.module.jsv.JsonSchemaValidator.*;
@Feature("JSON Schema Validation Testing")
public class BasicSchemaValidationTest {
@Test
@Description("Test JSON Schema validation for a single post")
public void testBasicSchemaValidation() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.log().all()
.when()
.get("/posts/1")
.then()
.statusCode(200)
.body(matchesJsonSchemaInClasspath("schemas/post-schema.json"));
}
}
Explanation:
matchesJsonSchemaInClasspath("schemas/post-schema.json")
: Validates the response against the schema in the classpath.log().all()
: Logs the request and response for debugging.- The test fails if the response doesn’t match the schema (e.g., missing fields, wrong types).
Important: Store schemas in src/test/resources
to ensure they’re available on the classpath during testing.
Example 2: Validating an Array of Objects
Validate a list of posts against a schema for an array.
Create a schema for an array of posts at src/test/resources/schemas/posts-array-schema.json
:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"userId": { "type": "integer" },
"title": { "type": "string" },
"body": { "type": "string" }
},
"required": ["id", "userId", "title", "body"],
"additionalProperties": false
}
}
Test code:
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 io.restassured.module.jsv.JsonSchemaValidator.*;
@Feature("JSON Schema Validation Testing")
public class ArraySchemaValidationTest {
@Test
@Description("Test JSON Schema validation for an array of posts")
public void testArraySchemaValidation() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.log().all()
.when()
.get("/posts")
.then()
.statusCode(200)
.body(matchesJsonSchemaInClasspath("schemas/posts-array-schema.json"));
}
}
Explanation:
- The schema defines an array where each item must match the post object structure.
- Validates that all posts in the response conform to the schema.
Example 3: Combining Schema Validation with Assertions
Combine schema validation with specific field assertions.
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 io.restassured.module.jsv.JsonSchemaValidator.*;
import static org.hamcrest.Matchers.*;
@Feature("JSON Schema Validation Testing")
public class SchemaWithAssertionsTest {
@Test
@Description("Test JSON Schema validation with specific assertions")
public void testSchemaWithAssertions() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.log().all()
.when()
.get("/posts/1")
.then()
.statusCode(200)
.body(matchesJsonSchemaInClasspath("schemas/post-schema.json"))
.body("id", equalTo(1))
.body("title", notNullValue());
}
}
Explanation:
- Combines
matchesJsonSchemaInClasspath()
with Hamcrest assertions for specific fields. - Ensures both structural and value-based validation.
Pro Tip: Use schema validation for structure and Hamcrest for specific value checks to balance thoroughness and flexibility.
Example 4: Schema Validation with Authentication
Validate a response from an authenticated endpoint using a mock Bearer token.
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 io.restassured.module.jsv.JsonSchemaValidator.*;
@Feature("JSON Schema Validation Testing")
public class AuthenticatedSchemaValidationTest {
@Test
@Description("Test JSON Schema validation with Bearer token")
public void testAuthenticatedSchemaValidation() {
RestAssured.baseURI = "https://httpbin.org";
// Mock authenticated request
given()
.header("Authorization", "Bearer my-bearer-token")
.log().all()
.when()
.get("/get")
.then()
.statusCode(200)
.body(matchesJsonSchemaInClasspath("schemas/httpbin-get-schema.json"))
.body("headers.Authorization", equalTo("Bearer my-bearer-token"));
}
}
Create a schema for the /get
response at src/test/resources/schemas/httpbin-get-schema.json
:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"args": { "type": "object" },
"headers": {
"type": "object",
"properties": {
"Authorization": { "type": "string" }
}
},
"url": { "type": "string" }
},
"required": ["args", "headers", "url"],
"additionalProperties": true
}
Explanation:
- Uses a mock Bearer token for authentication.
- Validates the response structure for the
/get
endpoint, which includes headers and URL. - Ensures the
Authorization
header is present in the response.
Example 5: Schema Validation with Response Specification
Use a ResponseSpecification to reuse schema validation logic.
import io.qameta.allure.Description;
import io.qameta.allure.*;
import io.restassured.RestAssured;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.specification.ResponseSpecification;
import org.junit.jupiter.api.*;
import static io.restassured.RestAssured.*;
import static io.restassured.module.jsv.JsonSchemaValidator.*;
import static org.hamcrest.Matchers.*;
@Feature("JSON Schema Validation Testing")
public class SchemaWithSpecTest {
private ResponseSpecification postSchemaSpec;
@BeforeEach
public void setup() {
postSchemaSpec = new ResponseSpecBuilder()
.expectStatusCode(200)
.expectBody(matchesJsonSchemaInClasspath("post-schema.json"))
.build();
}
@Test
@Description("Test JSON Schema validation with Response Specification")
public void testSchemaWithSpec() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.log().all()
.when()
.get("/posts/1")
.then()
.spec(postSchemaSpec)
.body("id", equalTo(1));
}
}
Explanation:
postSchemaSpec
: Defines a specification that includes schema validation.spec(postSchemaSpec)
: Applies the specification for reusable validation.Adds test-specific assertions for the
id
field.
Integrating with Allure Reporting
Document schema validation tests with Allure, attaching request and schema details.
import io.qameta.allure.*;
import io.restassured.*;
import io.restassured.response.Response;
import org.junit.jupiter.api.*;
import static io.restassured.RestAssured.*;
import static io.restassured.module.jsv.JsonSchemaValidator.*;
@Feature("JSON Schema Validation Testing")
public class AllureSchemaTest {
@Test
@Description("Test JSON Schema validation with Allure reporting")
public void testSchemaWithAllure() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
Response response = given()
.log().all()
.when()
.get("/posts/1")
.then()
.statusCode(200)
.body(matchesJsonSchemaInClasspath("schemas/post-schema.json"))
.extract().response();
Allure.addAttachment("Response Body", "application/json", response.asString(), ".json"));
// Attach schema file to allure
try (InputStream schemaStream = getClass().getResourceAsStream("/schemas/post-schema.json")) {
Allure.addAttachment("JSON Schema", "application/json", new String(schemaStream.readAllBytes()), ".json");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Explanation:
Allure.addAttachment
: Attaches the response body and schema file to the Allure report.mvn clean test
andmvn allure:serve
to to view the the report.
Integrating with CI/CD Pipeline
Add schema validation tests to a GitHub Actions pipeline for automation.
Create or update .github/workflows/ci.yml
:
name: REST Assured CI
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@v3
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
pExplanation:
- Runs schema validation tests with
mvn clean test
. - Publishes Allure reports to GitHub Pages for visibility.
Tips for Beginners
- Create Simple Schemas: Start with basic schemas and add constraints gradually (e.g., minLength, pattern).
- Store Schemas in Resources: Keep schemas in
src/test/resources
for easy classpath access. - Debug Schema Failures: Use
log().all()
to inspect responses and schema error messages for mismatches. - Reuse Schemas: Define schemas for common endpoints and reuse them with ResponseSpecs.
pTroubleshooting Tip: If schema validation fails, check the schema for errors (e.g., typos, missing fields) and enable verbose logging to compare the response JSON with the schema requirements.
What’s Next?
This post enhances our REST Assured series by introducing JSON Schema Validation, a critical tool for ensuring API data integrity. 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.
Stay tuned for more testing tutorials!