Deserialize Json Response
This tutorial will talk about a very interesting and helpful technique to read Body from a Response (Deserialize Json Response). This technique is called Deserialization of Response. Serialization and Deserialization are programming techniques where we convert Objects to Byte Streams and from Byte Streams back to Objects. This technique, in its very crude form, is discussed here Serialization and Deserialization in Java.
Before we start, it is very important that you go through the previous set of Tutorials. You can take a look at the tutorials here
How to Deserialize JSON Response to Class with Rest Assured?
Let us continue with our previous chapter Making a POST request using Rest-Assured. In the previous chapter, we made a successful post request and the following Response body was received.
{
"SuccessCode": "OPERATION_SUCCESS",
"Message": "Operation completed successfully"
}
We used JsonPath to validate parts of the Response body. Know we will convert this Response body into a Java Class. Representing a JSON, or any structured data including XML, into a programming class is called Deserialization of JSON. The term Deserialization here means the conversion from the String form of JSON to a Class form. This is also called Object Representation of structured data. Here structured data is the JSON.
In order to convert the JSON into a Class representation, we will first create a class that has all the nodes present in the JSON. The Success response above has two nodes
- SuccessCode
- Message
The value of these two nodes is String. Below image shows the parts of the response.
To represent such a Json we will need a class with two String variables, each representing the node in the Json. Below is the class code. Pay attention to the code comments for finer details
@Test
public class RegistrationSuccessResponse {
// Variable where value of SuccessCode node
// will be copied
// Note: The name should be exactly as the node name is
// present in the Json
public String SuccessCode;
// Variable where value of Message node will
// be copied
// Note: The name should be exactly as the node name is
// present in the Json
public String Message;
}
Now we have a RegistrationSuccessResponse class that can store all the nodes present in Success Response. Let us understand how we can use Rest-Assured to automatically convert Response Body Json to the instance of the RegistrationSuccessResponse class.
From previous tutorials we know that a Response body in Rest-Assured is represented by io.restassured.response.ResponseBody class. This class has a method called .as(Class<T>
). Where Class<T>
is a generic form of any class of type T. In our case Class<T>
is RegistrationSuccessResponse.
This method call will internally do two things
- Create an instance of RegistrationSuccessResponse class.
- Then copy the Node value of Json to the respective variable in the Class. For e.g. Value of SuccessCode node to the Variable SucessCode in the class.
To visualize it, let us look at the image below.
Below is the code that uses the Response.Body.as(Class<T>
) method.
@Test
public void RegistrationSuccessful()
{
RestAssured.baseURI ="https://restapi.demoqa.com/customer";
RequestSpecification request = RestAssured.given();
JSONObject requestParams = new JSONObject();
requestParams.put("FirstName", "Virender"); // Cast
requestParams.put("LastName", "Singh");
requestParams.put("UserName", "63userf2d3d2011");
requestParams.put("Password", "password1");
requestParams.put("Email", "ed26dff39@gmail.com");
request.body(requestParams.toJSONString());
Response response = request.post("/register");
ResponseBody body = response.getBody();
// Deserialize the Response body into RegistrationSuccessResponse
RegistrationSuccessResponse responseBody = body.as(RegistrationSuccessResponse.class);
// Use the RegistrationSuccessResponse class instance to Assert the values of
// Response.
Assert.assertEquals("OPERATION_SUCCESS", responseBody.SuccessCode);
Assert.assertEquals("Operation completed successfully", responseBody.Message);
}
Let us also see the responeBody variable in Debugger to see what values it gets. We will put a break point just after line number 18, below image shows the values of responseBody
Now you can use the responseBody variable to apply any assertions that you want or may be pass it as an input to other tests.
// Use the RegistrationSuccessResponse class instance to Assert the values of
// Response.
Assert.assertEquals("OPERATION_SUCCESS", responseBody.SuccessCode);
Assert.assertEquals("Operation completed successfully", responseBody.Message);
How to Deserialize JSON Response Body based on Response Status?
In real life it is possible for a REST Api endpoint to return multiple Json formats. For e.g. the API in this tutorial can return a completely different response in case of Failures. Below is the Json that is returned in failure cases.
{
"FaultId": "User already exists",
"fault": "FAULT_USER_ALREADY_EXISTS"
}
If we try to Deserialize this response into RegistrationSuccessResponse, it will not work. The reason is that while Deserializing Rest-Assured will not be able to find SuceessCode and Message fields in the Response body. As a result the two variables will be set to null.
So how do we handle these cases? This particular case of Success and Failure can be easily catered using the returned Status code. API in this tutorial returns 201 status code in case of Success and 200 in case of Error. We will also need another class that represents the failure Json Response.
We can see that there are two nodes that are present in Failure cases.
- FaultId
- fault
Below is the class that can represent a Failure response.
public class RegistrationFailureResponse {
String FaultId;
String fault;
}
To determine which scenario to execute we can simply put an if check in the Test code. Below is the updated Test code.
@Test
public void RegistrationSuccessful()
{
RestAssured.baseURI ="https://restapi.demoqa.com/customer";
RequestSpecification request = RestAssured.given();
JSONObject requestParams = new JSONObject();
requestParams.put("FirstName", "Virender"); // Cast
requestParams.put("LastName", "Singh");
requestParams.put("UserName", "63userf2d3d2011");
requestParams.put("Password", "password1");
requestParams.put("Email", "ed26dff39@gmail.com");
request.body(requestParams.toJSONString());
Response response = request.post("/register");
ResponseBody body = response.getBody();
System.out.println(response.body().asString());
if(response.statusCode() == 200)
{
// Deserialize the Response body into RegistrationFailureResponse
RegistrationFailureResponse responseBody = body.as(RegistrationFailureResponse.class);
// Use the RegistrationFailureResponse class instance to Assert the values of
// Response.
Assert.assertEquals("User already exists", responseBody.FaultId);
Assert.assertEquals("FAULT_USER_ALREADY_EXISTS", responseBody.fault);
}
else if (response.statusCode() == 201)
{
// Deserialize the Response body into RegistrationSuccessResponse
RegistrationSuccessResponse responseBody = body.as(RegistrationSuccessResponse.class);
// Use the RegistrationSuccessResponse class instance to Assert the values of
// Response.
Assert.assertEquals("OPERATION_SUCCESS", responseBody.SuccessCode);
Assert.assertEquals("Operation completed successfully", responseBody.Message);
}
}
Note: This is not the most ideal way of handling these types of cases. If possible we should rely on Inheritance to cater to varied Responses being returned by an API endpoint. In coming tutorials, we will see how we can implement an inheritance chain to handle these cases.