How to serialize JSON API requests using Java Records?

posted 5 min read

JSON is a popularly used file format in the APIs as it is lightweight and self-describing.
JSON stands for JavaScript Object Notation and. It was derived from JavaScript and originally specified by Douglas Crockford.

JSON is easy to read, write, and language-independent, supporting data structures like arrays and objects for flexible organization. It is widely used by software teams and is a common choice for storing and transferring data. The RESTful APIs generally rely on JSON files to exchange data over HTTP.

In this tutorial blog we will learn to serialize the JSON API requests using Java Records.

What are Java Records?

A Java record is a special type of class designed specifically for working with immutable data. Java Records were introduced in Java 14 version as a preview feature and became a standard feature in Java 16.

Records offer a concise syntax for defining classes primarily intended to store immutable data.

The following is a simple example of Java Records:

public record Country(String name, long population) {
}

What is JSON Serialization?

JSON serialization is the process of transforming an object, data structure, or complex data type into a JSON (JavaScript Object Notation) format. For example, converting Java POJO into a JSON format.

During JSON serialization, each attribute of an object is converted into a JSON property, while nested structures (such as lists or other objects) are represented as JSON arrays or nested JSON objects. This helps in making the data more portable and accessible to other systems, programming languages, or APIs.

For example consider the following “Country” object using Java Records:

public record Country(String name, long population) {
}

With JSON serialization, an instance of the “Country” Record could be converted to JSON as shown below:

{
"name" : "India",
     "population":  "1.43 billion"
}

How to serialize JSON API Requests using Java Records?

API requests using request body in the JSON format can be serialized using Java Records easily through the Jackson Databind or Google Gson library. Java Records are convenient, lightweight and efficient as they automatically generate getters, as well as equals(), hashCode(), and toString() methods.

In this tutorial, we will be using the Rest-Assured library for executing the API requests and Jackson Databind library with Java Records for serializing the request body used in the API requests.

API under Test

We will be using the restful-ecommerce APIs in this blog for demonstration. It is free to use E-Commerce Web APIs for practicing API testing and is available over GitHub.

We will be using the docker-compose file to start the restful-ecommerce application and accordingly execute the API requests on our local machine.

Test Scenario

We will use the “/addOrder” API that will allow adding new orders in the system. The following is the request payload for the “/addOrder” API:

[ { 
    "user_id": "1",
    "product_id": "1",
    "product_name": "iPhone",
    "product_amount": 500.00,
    "qty": 1,
    "tax_amt": 5.99,
    "total_amt": 505.99
}]

The request accepts a JSON array with multiple JSON objects that holds the different order details.

We will serialize the JSON given in the payload using Java Records and execute the POST request to add order in the system verifying that the order is added successfully.

Configuration

We would be using the Maven project and adding the following dependencies in the pom.xml file.

<dependency>
   <groupId>org.testng</groupId>
   <artifactId>testng</artifactId>
   <version>7.10.2</version>
 </dependency>

 <dependency>
   <groupId>io.rest-assured</groupId>
   <artifactId>rest-assured</artifactId>
   <version>5.5.0</version>
   <scope>test</scope>
 </dependency>

 <dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
   <version>2.18.1</version>
 </dependency>
 <dependency>

The dependencies are for TestNG that acts as a test runner, rest-assured for executing the API requests and Jackson Databind that will help in serialization.

Let’s create a new package - restful-ecommerce under the src/test folder in the project.

Let’s add two more packages under the restful-ecommerce page, the first one with name - pojo and the second one with name tests.

Test Implementation

The first step in implementation is to create Java Records with the fields needed for adding the Order as per the request payload.

The request payload requires the following fields, hence we will accordingly add those fields to the Record

  1. user_id
  2. product_id
  3. product_name
  4. product_amt
  5. qty
  6. tax_amt
  7. total_amt

The data_type details for these fields can be found on the Swagger using which the fields in the Java Record can be created.

So, let’s add a new Java Record - “Order”, under the pojo package.

public record Order(String user_id, String product_id, String product_name, int product_amount, int qty, int tax_amt,
                   int total_amt) {
}

After adding the Java Record, we can straightaway move to write the API tests and create a new Java class - “AddOrderTests” under the tests package.

public class AddOrderTests {

@Test
public void testAddOrder () {

   List<Order> orders = new ArrayList<> ();
   orders.add (new Order ("1", "34", "Canon Camera CX12", 14500, 1, 915, 15415));

   given ().body (orders)
       .when ()
       .log ()
       .all ()
       .contentType (ContentType.JSON)
       .post ("http://localhost:3004/addOrder")
       .then ()
       .log ()
       .all ()
       .statusCode (201);

}
}

Code Walkthrough

The @Test annotation is from the TestNG library that will allow us to run the tests. The request payload actually accepts JSON Arrays in which multiple objects of Orders are added.

List<Order> orders = new ArrayList<> ();

The first statement in the method is creating a new list that can store Order objects. This will help us in adding multiple order objects to the list and accordingly pass them as the request body. This is done to ensure that we pass the JSON Object under JSON Arrays as the "/addOrder" endpoint needs the request body in JSON Array format.

orders.add (new Order ("1", "34", "Canon Camera CX12", 14500, 1, 915, 15415));

The second line in the method adds an object of Order with details. See how simple it is to pass the value to the Records object, Records automatically generates the required constructor for passing the values.

Next, using rest-assured methods the test for the API is written.

given ().body (orders)
   .when ()
   .log ()
   .all ()
   .contentType (ContentType.JSON)
   .post ("http://localhost:3004/addOrder")
   .then ()
   .log ()
   .all ()
   .statusCode (201);

The interpretation of the above code is pretty simple: given a body of order objects, log the request details in the console, the content-type of the request body will be in JSON format.

The Post HTTP method should be hit for the API endpoint http://localhost:3004/addOrder”, when the API is executed, then the response details received should be logged in the console and its status code should be checked that should be equal to 201.

Test Execution

Before we execute the test, we should make sure that the restful-ecommerce application is up and running. We can start the application using the following docker compose command:

docker compose -f docker-files/docker-compose-ecommerce.yml up -d

We can then hit the following URL to make sure that the application is up and running. It should display the Swagger docs

http://localhost:3004/api-docs/

Next, we can run the test and check for the output. The following screenshots show that the JSON is serialized successfully in the API request body.

The addOrder API is successfully hit and one order is generated.

Summary

Java Records introduced in Java 16 are convenient, lightweight and efficient as they automatically generate getters, as well as equals(), hashCode(), and toString() methods.

It can be a better fit for JSON serialization and deserialization with Jackson Databind library as it does not require writing a lot of boilerplate code.

All the code examples shown in this article can be found over on GitHub.

Happy Testing!

If you read this far, tweet to the author to show them you care. Tweet a Thanks
Great tutorial! The example with Java Records for JSON serialization is very clear and easy to follow. Just curious, how would you approach error handling or validation when working with serialized data in API requests?
Rest-Assured already has the mechanism for handling the errors and providing us with the required details in the console if anything goes wrong. Another approach that could be tried is using the try/catch block.

More Posts

Creating RESTful API Using Spring Boot for The First Time

didikts - Oct 14

Learn how to write GenAI applications with Java using the Spring AI framework and utilize RAG for improving answers.

Jennifer Reif - Sep 22

Java Features You Didn’t Know Existed (But Should)

saurabhkurve - Dec 11

Invalid Method Declaration; Return Type Required in Java

Abdul Daim - Feb 22

Solved Incompatible types: possible lossy conversion from double to int

prince yadav - Oct 14, 2023
chevron_left