Introduction
Application Programming Interface becomes the backbone of programming, which helps in communicating between two different systems. As a tester, we need to give maximum test coverage for API calls validation in integration testing. This can be achieved by automating the API calls to increase efficiency.
Rest API calls will be validated using different open-source automation tools like SoapUI, Katalon studio, Rest-Assured, Karate, etc.
Here we are going to discuss Rest Assured libraries for validating API calls. The first step is to get this library integrated with the java projects. These library classes facilitate the developer/tester in framing the request with different parameters and helps in retrieving the response in standard formats like XML/JSON and helps in taking logs of request and response details for each API call.
Pre-requisites
The reader should be aware of creating Maven Project in any IDE like Eclipse, IntelliJ, Atom having basic knowledge about API calls.
Components in Rest-Assured
The significant functionality of the Rest Assured library is Request and Response. Request functionality covers composing of Base URI, Resource Path, Query / Form parameters, Authorization keys, Header, and Body. Then request call is made by any methods like GET, POST, PUT and more to the server and retrieve its response. For composing the request, we have Request Specification and RequestSpecBuilder classes in the Rest-Assured library.
For validating the response received from the server, we have a Response class. It helps extract the response content as JSON/XML format, to verify status, response header & body. It supports to handle the storing of request and response logs while making validation of calls using RequestLoggingFilter and ResponseLoggingFilter classes.
Singleton class has one instance of common request forming and response validation. It provides global access to the instance, so here framing requests, retrieving responses, and logs are easily handled for code reusability.
Demonstrate API calls validation using Singleton Design Pattern
Let’s see the below example,
- Add Book details in the record using the POST method
- Retrieve Book details under author name using the GET method
Method | URL Format | Purpose |
POST | https://BaseURI/ResourcePath | To add book details in the Record |
GET | https://BaseURI/ResourcePath?QueryParam=Value | To get Book with author-name |
Steps to automate these API using Rest-Assured Libraries
Step 1: Create a Maven Project with dependency
Include latest TestNG and Rest-Assured dependencies in pom.xml file
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.1.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.1.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
Step 2: Create a Singleton class for handling major actions.
For singleton class, the static instance variable here is SingletonRA RA, which can be instantiated only in its class for once. Here the request is formed in two-stages, The first one in the respect method the standard headers, forming the log file, and in the second stage of request with service-specific details like query, params are added in variable res in getRes method.
import io.restassured.RestAssured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.filter.log.RequestLoggingFilter;
import io.restassured.filter.log.ResponseLoggingFilter;
import io.restassured.http.ContentType;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Paths;
/*single instance variable of the class*/
privatestatic SingletonRA RA;
/*creating instance of singleton class*/
publicstatic SingletonRA getInstance()
/*RequestSpecification used to form basic request*/
public RequestSpecification reqSpec()throws FileNotFoundException {
RequestSpecification req = newRequestSpecBuilder()
.setBaseUri("http://baseuri")
.addFilter(RequestLoggingFilter.logRequestTo(newPrintStream(newFileOutputStream("log1.txt"))))
.addFilter(ResponseLoggingFilter.logResponseTo(newPrintStream(newFileOutputStream("log.txt"))))
.setContentType(ContentType.JSON).build();
/* Obtaining Response by providing particular resource and
* payload specific to services
* in the RequestSpecification from reqSpec */
/* To use single getRes method for all protocol, making path variable as
* optional in this method, Say for POST method we need resource and payload
* path but for GET method variable resource alone sufficient.*/
public Response getRes(String resource,String... path){
RequestSpecification res;
Response response = null;
/*Optional variable comes as array so convert them into string*/
StringBuffer sb =newStringBuffer();
for(int i=0;i<path.length;i++){
/*For Adding Book using POST method*/
if(resource.contains("Library/Addbook.php")){
res = RestAssured.given().spec(reqSpec()).
body(GenerateStringFromResource(sb.toString()));
response =res.when().post(resource);
/*For retrieve Book details using Author in GET Method*/
elseif(resource.contains("Library/GetBook.php")){
res = RestAssured.given().spec(reqSpec()).queryParam("AuthorName","Selva");
response = res.when().get(resource);
/*Load payload from json file*/
publicstaticStringGenerateStringFromResource(String path)throws IOException {
returnnewString(Files.readAllBytes(Paths.get(path)));
package RestAssured;
import io.restassured.RestAssured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.filter.log.RequestLoggingFilter;
import io.restassured.filter.log.ResponseLoggingFilter;
import io.restassured.http.ContentType;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Paths;
public class SingletonRA
{
/*Private Constructor*/
private SingletonRA() {}
/*single instance variable of the class*/
private static SingletonRA RA;
/*creating instance of singleton class*/
public static SingletonRA getInstance()
{
if(RA ==null)
{
RA = new SingletonRA();
}
return RA;
}
/*RequestSpecification used to form basic request*/
public RequestSpecification reqSpec() throws FileNotFoundException {
RequestSpecification req = new RequestSpecBuilder()
.setBaseUri("http://baseuri")
.addFilter(RequestLoggingFilter.logRequestTo(new PrintStream(new FileOutputStream("log1.txt"))))
.addFilter(ResponseLoggingFilter.logResponseTo(new PrintStream(new FileOutputStream("log.txt"))))
.setContentType(ContentType.JSON).build();
return req;
}
/* Obtaining Response by providing particular resource and
* payload specific to services
* in the RequestSpecification from reqSpec */
/* To use single getRes method for all protocol, making path variable as
* optional in this method, Say for POST method we need resource and payload
* path but for GET method variable resource alone sufficient.*/
public Response getRes(String resource,String... path){
RequestSpecification res;
Response response = null;
/*Optional variable comes as array so convert them into string*/
StringBuffer sb =new StringBuffer();
for(int i=0;i<path.length;i++) {
sb.append(path[i]);
}
try{
/*For Adding Book using POST method*/
if(resource.contains("Library/Addbook.php")){
res = RestAssured.given().spec(reqSpec()).
body(GenerateStringFromResource(sb.toString()));
response =res.when().post(resource);
return response;
}
/*For retrieve Book details using Author in GET Method*/
else if (resource.contains("Library/GetBook.php")){
res = RestAssured.given().spec(reqSpec()).queryParam("AuthorName","Selva");
response = res.when().get(resource);
return response;
}
}catch(Exception e){
e.printStackTrace();
}
return response;
}
/*Load payload from json file*/
public static String GenerateStringFromResource(String path) throws IOException {
return new String(Files.readAllBytes(Paths.get(path)));
}
}
package RestAssured;
import io.restassured.RestAssured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.filter.log.RequestLoggingFilter;
import io.restassured.filter.log.ResponseLoggingFilter;
import io.restassured.http.ContentType;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Paths;
public class SingletonRA
{
/*Private Constructor*/
private SingletonRA() {}
/*single instance variable of the class*/
private static SingletonRA RA;
/*creating instance of singleton class*/
public static SingletonRA getInstance()
{
if(RA ==null)
{
RA = new SingletonRA();
}
return RA;
}
/*RequestSpecification used to form basic request*/
public RequestSpecification reqSpec() throws FileNotFoundException {
RequestSpecification req = new RequestSpecBuilder()
.setBaseUri("http://baseuri")
.addFilter(RequestLoggingFilter.logRequestTo(new PrintStream(new FileOutputStream("log1.txt"))))
.addFilter(ResponseLoggingFilter.logResponseTo(new PrintStream(new FileOutputStream("log.txt"))))
.setContentType(ContentType.JSON).build();
return req;
}
/* Obtaining Response by providing particular resource and
* payload specific to services
* in the RequestSpecification from reqSpec */
/* To use single getRes method for all protocol, making path variable as
* optional in this method, Say for POST method we need resource and payload
* path but for GET method variable resource alone sufficient.*/
public Response getRes(String resource,String... path){
RequestSpecification res;
Response response = null;
/*Optional variable comes as array so convert them into string*/
StringBuffer sb =new StringBuffer();
for(int i=0;i<path.length;i++) {
sb.append(path[i]);
}
try{
/*For Adding Book using POST method*/
if(resource.contains("Library/Addbook.php")){
res = RestAssured.given().spec(reqSpec()).
body(GenerateStringFromResource(sb.toString()));
response =res.when().post(resource);
return response;
}
/*For retrieve Book details using Author in GET Method*/
else if (resource.contains("Library/GetBook.php")){
res = RestAssured.given().spec(reqSpec()).queryParam("AuthorName","Selva");
response = res.when().get(resource);
return response;
}
}catch(Exception e){
e.printStackTrace();
}
return response;
}
/*Load payload from json file*/
public static String GenerateStringFromResource(String path) throws IOException {
return new String(Files.readAllBytes(Paths.get(path)));
}
}
Step 3: Create a Test class for writing TestNG tests.
For the Post method, we need to pass the payload and resource to get a response, and for the GET method, the only help is required to be given. Here for adding Book details into a record, we are passing Payload in Json file location. The resource for each request differs, so each service needs to test with its resources passing through Tests.
import java.util.ArrayList;
import org.testng.annotations.Test;
import io.restassured.path.json.JsonPath;
/*Get instance of singleton class*/
SingletonRA RA = SingletonRA.getInstance();
String payloadPath =".\\src\\resources\\postBook.json";
String resource = "Library/Addbook.php";
/*Pass the payload location and resource for the API*/
String Response = RA.getRes(resource,payloadPath).asString();
/*Using Jsonpath get msg field in response*/
JsonPath js = newJsonPath(Response);
String msg = js.getString("msg");
/*Validate the msg and display corresponding display message*/
if(msg.contains("operation failed")){
System.out.println("Given Book details are already present in record");
}elseif(msg.contains("successfully")){
System.out.println("Given Book details are added in record");
System.out.println("Rest API is not working as expected");
publicvoidgetBookbyAuthor(){
String resource = "Library/GetBook.php";
/*Pass the resource to get response*/
String Response = RA.getRes(resource).asString();
JsonPath js = newJsonPath(Response);
System.out.println(js.get("book_name"));
ArrayList<String> books = js.get("book_name");
/*Verify the count of books present under author name*/
System.out.println(books.size() + " Books are present for the author");
package RestAssured;
import java.util.ArrayList;
import org.testng.annotations.Test;
import io.restassured.path.json.JsonPath;
public class TestRA
{
/*Get instance of singleton class*/
SingletonRA RA = SingletonRA.getInstance();
@Test
public void addBook(){
String payloadPath =".\\src\\resources\\postBook.json";
String resource = "Library/Addbook.php";
/*Pass the payload location and resource for the API*/
String Response = RA.getRes(resource,payloadPath).asString();
/*Using Jsonpath get msg field in response*/
JsonPath js = new JsonPath(Response);
String msg = js.getString("msg");
/*Validate the msg and display corresponding display message*/
if(msg.contains("operation failed")) {
System.out.println("Given Book details are already present in record");
}else if(msg.contains("successfully")) {
System.out.println("Given Book details are added in record");
}else {
System.out.println("Rest API is not working as expected");
}
}
@Test
public void getBookbyAuthor() {
String resource = "Library/GetBook.php";
/*Pass the resource to get response*/
String Response = RA.getRes(resource).asString();
JsonPath js = new JsonPath(Response);
System.out.println(js.get("book_name"));
ArrayList<String> books = js.get("book_name");
/*Verify the count of books present under author name*/
if(books.size()>0) {
System.out.println(books.size() + " Books are present for the author");
}
}
}
package RestAssured;
import java.util.ArrayList;
import org.testng.annotations.Test;
import io.restassured.path.json.JsonPath;
public class TestRA
{
/*Get instance of singleton class*/
SingletonRA RA = SingletonRA.getInstance();
@Test
public void addBook(){
String payloadPath =".\\src\\resources\\postBook.json";
String resource = "Library/Addbook.php";
/*Pass the payload location and resource for the API*/
String Response = RA.getRes(resource,payloadPath).asString();
/*Using Jsonpath get msg field in response*/
JsonPath js = new JsonPath(Response);
String msg = js.getString("msg");
/*Validate the msg and display corresponding display message*/
if(msg.contains("operation failed")) {
System.out.println("Given Book details are already present in record");
}else if(msg.contains("successfully")) {
System.out.println("Given Book details are added in record");
}else {
System.out.println("Rest API is not working as expected");
}
}
@Test
public void getBookbyAuthor() {
String resource = "Library/GetBook.php";
/*Pass the resource to get response*/
String Response = RA.getRes(resource).asString();
JsonPath js = new JsonPath(Response);
System.out.println(js.get("book_name"));
ArrayList<String> books = js.get("book_name");
/*Verify the count of books present under author name*/
if(books.size()>0) {
System.out.println(books.size() + " Books are present for the author");
}
}
}
Request Log for POST method :
Request URI: http://<baseuri>/Library/Addbook.php
Content-Type=application/json; charset=UTF-8
"name": "Bedtime stories-Kings",
Request method: POST
Request URI: http://<baseuri>/Library/Addbook.php
Proxy: <none>
Request params: <none>
Query params: <none>
Form params: <none>
Path params: <none>
Headers: Accept=*/*
Content-Type=application/json; charset=UTF-8
Cookies: <none>
Multiparts: <none>
Body:
{
"name": "Bedtime stories-Kings",
"isbn": "KID",
"aisle": "006",
"author": "Krishna"
}
Request method: POST
Request URI: http://<baseuri>/Library/Addbook.php
Proxy: <none>
Request params: <none>
Query params: <none>
Form params: <none>
Path params: <none>
Headers: Accept=*/*
Content-Type=application/json; charset=UTF-8
Cookies: <none>
Multiparts: <none>
Body:
{
"name": "Bedtime stories-Kings",
"isbn": "KID",
"aisle": "006",
"author": "Krishna"
}
Response Log for POST method :
Date: Fri, 06 Mar 202011:04:14 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST
Access-Control-Max-Age: 3600
Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With
Keep-Alive: timeout=5, max=100
Transfer-Encoding: chunked
Content-Type: application/json;charset=UTF-8
"Msg": "successfully added",
HTTP/1.1 200 OK
Date: Fri, 06 Mar 2020 11:04:14 GMT
Server: Apache
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST
Access-Control-Max-Age: 3600
Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/json;charset=UTF-8
{
"Msg": "successfully added",
"ID": "KID006"
}
HTTP/1.1 200 OK
Date: Fri, 06 Mar 2020 11:04:14 GMT
Server: Apache
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST
Access-Control-Max-Age: 3600
Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/json;charset=UTF-8
{
"Msg": "successfully added",
"ID": "KID006"
}
Thanks for spending time reading. Please share your queries and feedback in the comments.