1

How do we assert the JSON response field type?

{
  "Data" : [
     "Id" : 1,
     "Name" : "ABC"
  ]
}

Is there any way to validate that ID should contain an int and Name should be a String? I don't want to validate the values.

andrewJames
  • 19,570
  • 8
  • 19
  • 51
Bob
  • 11
  • 1
  • Do you want to make sure the value gets set as a specific type or want to know what type it is while reading it? In Json itself there are no fixed datatypes if this answers your question. – Japhei Jul 07 '22 at 20:43
  • 2
    Dear @Bob, Welcome to Stack Overflow! Please, note that the provided JSON document is not valid. Should `Data` be an array of objects or an object? Could you please correct the JSON document? – Sergey Vyacheslavovich Brunov Jul 07 '22 at 20:44
  • Try looking at [Validate JSON Schema in Rest Assured](https://www.tutorialspoint.com/validate-json-schema-in-rest-assured). – Alias Cartellano Jul 07 '22 at 21:39
  • @Japhei I want to validate the type. For example, For Name the value should be in String only. //This Should Fail as we got Name is not in String. { "Data" : [ "Id" : 1, "Name" :ABC ] } //Valid one, It should pass { "Data" : [ "Id" : 1, "Name" : "ABC" ] } – Bob Jul 08 '22 at 03:48
  • @Bob again, when so you want to validate it? While reading the file or while writing it? There is no way to just tell Json to only accept specific datatypes. – Japhei Jul 08 '22 at 08:11

1 Answers1

1

Overview

You are asking how to check the JSON document structure.
JSON document validation against a JSON schema (JSON schema validation) is a way to perform such check.

Introduction

Let's consider the following versions as the current versions:

  • REST Assured: 5.1.1.
  • JUnit: 5.8.2.

Solution

REST Assured supports JSON schema validation.

Draft example unit test

The unit test class contain two tests: successful and failing.

The failing test fails with the following message:

java.lang.AssertionError: 1 expectation failed.
Response body doesn't match expectation.
Expected: The content to match the given JSON schema.
error: instance type (object) does not match any allowed primitive type (allowed: ["string"])
    level: "error"
    schema: {"loadingURI":"file:/<the-project-path>/target/test-classes/schema.json#","pointer":"/properties/Data/items/0/properties/Name"}
    instance: {"pointer":"/Data/0/Name"}
    domain: "validation"
    keyword: "type"
    found: "object"
    expected: ["string"]

  Actual: {
  "Data": [
    {
      "Id": 1,
      "Name": {
        "FirstName": "First",
        "LastName": "Last"
      }
    }
  ]
}

Maven project (pom.xml)

<properties>
    <restassured.version>5.1.1</restassured.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.8.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.rest-assured</groupId>
        <artifactId>rest-assured</artifactId>
        <version>${restassured.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.rest-assured</groupId>
        <artifactId>json-schema-validator</artifactId>
        <version>${restassured.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.github.tomakehurst</groupId>
        <artifactId>wiremock-jre8</artifactId>
        <version>2.33.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

JSON schema (src/test/resources/schema.json)

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "Data": {
      "type": "array",
      "items": [
        {
          "type": "object",
          "properties": {
            "Id": {
              "type": "integer"
            },
            "Name": {
              "type": "string"
            }
          },
          "required": [
            "Id",
            "Name"
          ]
        }
      ]
    }
  },
  "required": [
    "Data"
  ]
}

Test data (src/test/resources/__files/data.json)

{
  "Data": [
    {
      "Id": 1,
      "Name": "ABC"
    }
  ]
}

Test data (src/test/resources/__files/data-invalid.json)

{
  "Data": [
    {
      "Id": 1,
      "Name": {
        "FirstName": "First",
        "LastName": "Last"
      }
    }
  ]
}

Unit test class (src/test/java/info/brunov/stackoverflow/question72903880/DataServiceTest.java)

package info.brunov.stackoverflow.question72903880;

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import io.restassured.RestAssured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.filter.log.LogDetail;
import io.restassured.module.jsv.JsonSchemaValidator;
import io.restassured.specification.RequestSpecification;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

public final class DataServiceTest {
    private final WireMockServer server;
    private final RequestSpecification requestSpecification;

    public DataServiceTest() {
        server = new WireMockServer(
            WireMockConfiguration.wireMockConfig().dynamicPort()
        );
        server.stubFor(
            WireMock.get("/data")
                .willReturn(
                    WireMock.aResponse().withBodyFile("data.json")
                )
        );
        server.stubFor(
            WireMock.get("/data-invalid")
                .willReturn(
                    WireMock.aResponse().withBodyFile("data-invalid.json")
                )
        );
        server.start();

        final RequestSpecBuilder requestSpecBuilder = new RequestSpecBuilder();
        requestSpecBuilder.setPort(server.port());
        requestSpecification = requestSpecBuilder.build();
    }

    @AfterEach
    void tearDown() {
        server.stop();
    }

    @Test
    public void getData_responseConformsSchema_success() {
        RestAssured.given()
            .spec(requestSpecification)
            .get("/data")
            .then()
            .log().ifValidationFails(LogDetail.ALL)
            .assertThat()
            .statusCode(200)
            .body(JsonSchemaValidator.matchesJsonSchemaInClasspath("schema.json"));
    }

    // NOTE: Deliberately failing test.
    @Test
    public void getInvalidData_responseConformSchema_fail() {
        RestAssured.given()
            .spec(requestSpecification)
            .get("/data-invalid")
            .then()
            .log().ifValidationFails(LogDetail.ALL)
            .assertThat()
            .statusCode(200)
            .body(JsonSchemaValidator.matchesJsonSchemaInClasspath("schema.json"));
    }
}