Skip to content

How To Share Data From One API To Another API 

Data sharing is a very important concept in API testing. There are many ways to share the data among the tests. In this article, we will cover how to share data from one API to another API.

What Is API Chaining

API chaining is the technique where we need to feed the output of one API as input to another API. This process helps us to validate the full functionality of API, not just the individual endpoints. For example, creating a user id needs to be used as input in updating users, deleting users, creating bookings for users etc.

The next step is to understand the scope of data sharing. For example, do we need the data to be shared across only methods in the same class? or across different classes?Or across different Tests? Once the requirement is clear and the scope is defined then we can choose the appropriate method as per our project needs.

How to share data among different APIs

There are multiple ways to share data from one API to another API. Some of them are as follows:

1)By Using Class level Variable

Scenario :

1) Create a new user (Post Request)
2) Get User detail (Get Request)

a)Create a class named User operations and create a global variable “UserId”.
b)Write test cases for Creating a new user. Fetch the “user-id” of the new user using “jsonpath()” method and store it in the “UserId” variable.

public class UserProfileTest {
private static final String URL = "https://reqres.in";
private int UserId;
@Test(priority=1)
public void CreateNewUser () {
    
       Response response = given ().contentType (ContentType.JSON)
            .body (Body)
            .when ()
            .post (URL + "/api/users")
            .then ()
            .assertThat ()
            .statusCode (201)
UserId =response.jsonPath().getInt("userid");
          
           }
}

c) Create a method in the same class to fetch user details of newly created users on the basis of the user-id that was stored in the global variable. Maintain the execution order by using the testNg Priority to avoid the unnecessary issue.

@Test(priority=2)    
public void getUserDetails ()  {
        given ().when ()
            .get (URL +"/"+UserId)
            .then ()
            .statusCode (200)
            .and ()
            .assertThat ()
            .body ("data.id", equalTo (UserId));
}

The disadvantage of this method is that data can be shared only within this class. If we need to pass UserId to different test class methods, it won’t be possible to use private class variables.

2)By Creating a Common Class

Create a common class and declare all those global variables in that class which are required for data sharing.

public class DataStore {
	
	public static String User_Token;
	public static String UserId;
	public static int ActivityId;
	}

Now modify the UserProfileTest class to store and fetch data from the DataStore class.

public class UserProfileTest {
private static final String URL = "https://reqres.in";
private static final Logger LOG = LogManager.getLogger (UserProfileTest.class);

@Test(priority=1)
public void CreateNewUser () {
    
       Response response = given ().contentType (ContentType.JSON)
            .body (Body)
            .when ()
            .post (URL + "/api/users")
            .then ()
            .assertThat ()
            .statusCode (201)
DataStore.UserId =response.jsonPath().getInt("userid");
Log.info("User Id of created user is:_"+DataStore.UserId);
}

@Test(priority=2)    
public void getUserDetails ()  {
        given ().when ()
            .get (URL +"/"+DataStore.UserId)
            .then ()
            .statusCode (200)
            .and ()
            .assertThat ()
            .body ("data.id", equalTo (UserId));
}
}

By using this approach we can share data among different classes. But this approach also has its limitations if we have to store and pass huge data then it’s not convenient to write 100 variables in the DataStore class and use it.

3)By Using TestNg ITestContext Interface

TestNg provides interfaces like ITestContext and ISuite, with the help of which data sharing is very easy. To use these interfaces TestNg dependency should be included in the project.

ITestContext:

 This interface defines a test context that contains all the information for a given test run. To Use this interface, pass it as a parameter in the method. Modify UserProfileTest class as mentioned below code to use the ITestContext interface for data sharing.

@Test(priority=1)
public void CreateNewUser (ITestContext context) {
    
       Response response = given ().contentType (ContentType.JSON)
            .body (Body)
            .when ()
            .post (URL + "/api/users")
            .then ()
            .assertThat ()
            .statusCode (201)
int UserId =response.jsonPath().getInt("userid");
context.setAttribute("UserId", UserId);
Log.info("User Id of created user is:_"+UserId);
}
@Test(priority=2)    
public void getUserDetails (ITestContext context)  {
        given ().when ()
            .get (URL +"/"+context.getAttribute("UserId"))
            .then ()
            .statusCode (200)
            .and ()
            .assertThat ()
            .body ("data.id", equalTo (UserId));
}

This approach also has one limitation. Suppose the “CreateNewUser” test is on the “UserProfileTest1” class and “getUserDetails” is written in another class “UserProfileTest2” and these 2 classes are defined in 2 different test runs. For example :

<suite name="All Tests Suite">

   <test thread-count="2" name="Test1">
	<classes>
	  <class name="UserProfileTest1" />
	</classes>
   </test> 
	
   <test thread-count="2" name="Test2">
	<classes>
	   <class name="UserProfileTest2" />
	</classes>
   </test>
</suite>

In the above case on execution, we will face a null pointer exception because as per the definition of ITestContext Interface data sharing is permissible in a single test run (<test> tag).

To overcome this issue we can modify our code to pass the data at the suite level rather than the test level.

Steps:

1)Update “context.setAttribute(“UserId”, UserId)” to “context.getSuite().setAttribute(“UserId”, UserId)”.

2)Update “context.getAttribute(“UserId”)” to “context.getSuite().getAttribute(“UserId”)”.

3)Modify the UserProfileTest1 class as below mentioned code.

public class UserProfileTest1 {
private static final String URL = "https://reqres.in";
private static final Logger LOG = LogManager.getLogger (UserProfileTest1.class);

@Test(priority=1)
public void CreateNewUser (ITestContext context) {
    
       Response response = given ().contentType (ContentType.JSON)
            .body (Body)
            .when ()
            .post (URL + "/api/users")
            .then ()
            .assertThat ()
            .statusCode (201)
int UserId =response.jsonPath().getInt("userid");
context.getSuite().setAttribute("UserId", UserId)
Log.info("User Id of created user is:_"+UserId);
}
}

4)Update the UserProfileTest2 class as below mentioned code.

public class UserProfileTest2 {
private static final String URL = "https://reqres.in";
private static final Logger LOG = LogManager.getLogger (UserProfileTest2.class);
@Test(priority=2)    
public void getUserDetails (ITestContext context)  {
        given ().when ()
            .get (URL +"/"+context.getSuite().getAttribute("UserId"))
            .then ()
            .statusCode (200)
            .and ()
            .assertThat ()
            .body ("data.id", equalTo (UserId));
}
}

Visit Here to learn how to build Rest assured Framework step by step.