RESTAPI
RESTAPI
Page | 2
Page | 3
I dedicate this book
to my beloved husband,
who loves me very much,
puts the world in front of him for me,
and who is always by my side.
Thank you for everything…
Page | 4
Contents
What will you learn in this book? ..................................................................................................................................... 7
What is Client Server Architecture? .................................................................................................................................. 7
What is HTTP Request? ................................................................................................................................................... 10
What is HTTP Response?................................................................................................................................................. 16
API Testing with Postman ............................................................................................................................................... 21
Download Postman and Install On Windows and MacOS .............................................................................................. 25
Postman Navigation ........................................................................................................................................................ 31
Create New Request in Postman .................................................................................................................................... 36
GET Requests in Postman ............................................................................................................................................... 39
Response in Postman ...................................................................................................................................................... 40
Request Parameters in Postman..................................................................................................................................... 45
POST Request using Postman ......................................................................................................................................... 50
What is REST?.................................................................................................................................................................. 57
What is Rest Api? ............................................................................................................................................................ 61
Rest Architectural Elements............................................................................................................................................ 64
Getting started with Rest Assured .................................................................................................................................. 68
Configure Eclipse with Rest-Assured .............................................................................................................................. 71
REST API Testing using Rest Assured .............................................................................................................................. 78
Validate Response Status using Rest Assured ................................................................................................................ 84
Validate Response Header using Rest Assured ............................................................................................................... 90
Read JSON Response Body using Rest Assured .............................................................................................................. 93
Working with Query Parameters in Rest Assured | REST API ......................................................................................... 98
Understanding HTTP POST Request Method using Rest Assured ................................................................................ 101
Serialization and Deserialization in Java ....................................................................................................................... 105
Deserialize JSON Response using Rest Assured ............................................................................................................ 111
Authentication and Authorization in REST WebServices .............................................................................................. 115
Basic Authentication ..................................................................................................................................................... 118
PUT Request using Rest Assured................................................................................................................................... 123
Page | 5
DELETE Request using Rest Assured ............................................................................................................................. 127
What is JSON? ............................................................................................................................................................... 132
JSONPath and Query JSON using JSONPath.................................................................................................................. 134
Expressions in JSONPath ............................................................................................................................................... 141
Deserialize JSON Array to List ....................................................................................................................................... 156
Deserialize JSON Array to an Array ............................................................................................................................... 159
What is API Documentation, and Why It Matters?....................................................................................................... 163
REST API End to End Test .............................................................................................................................................. 171
REST API Test in Cucumber ........................................................................................................................................... 179
Convert JSON Request Body to JAVA Object ................................................................................................................ 190
Convert JSON Response Body to Java Object ............................................................................................................... 205
Separation of Test Layer with API Services ................................................................................................................... 217
Implementation of REST Routes ................................................................................................................................... 226
Implementation of Generics in API Framework............................................................................................................ 232
Refactoring for Request Headers .................................................................................................................................. 242
Share Test Context in Cucumber .................................................................................................................................. 249
Share Scenario Context in Cucumber ........................................................................................................................... 255
Implement Configuration Reader ................................................................................................................................. 263
Rest Assured Examples ................................................................................................................................................. 271
Page | 6
What will you learn in this book?
Rest Assured Tutorial for REST API Automation Testing
This is a series of Rest Assured Tutorial which is one of the most used library
for REST API Automation Testing. Rest-Assured is a Java-based library that is
used to test RESTful Web Services. This library behaves like a headless Client
to access REST web services. We can create highly customize-able HTTP
Requests to send to the Restful server. This enables us to test a wide variety of
Request combinations and in turn test different combinations of core business
logic.
Rest-Assured library also provides the ability to validate the HTTP Responses received from the server. For e.g. we
can verify the Status code, Status message, Headers and even the Body of the response. This makes Rest-Assured a
very flexible library that can be used for testing.
o What is a client?
o What is a server?
Client server architecture in a simple sense can be stated as a consumer-producer model where the client acts as the
consumer i.e. the service requestor and the server is the producer, i.e. the service provider. Let us see how they are
described in the computing sense.
What is a Client?
A client in computing is a system or a program that connects with a remote system or software to fetch information.
The client makes a request to the server and is responded with information. There may be three types of clients -
thick, thin or hybrid client.
• A thick or fat client performs the operation itself without the need for a server. A personal computer is a fine
example of a thick client as the majority of its operations are independent of an external server.
• A thin client uses the host computer's resources, where the thin client presents the data processed by an
application server. A web browser is an example of a thin client.
• A hybrid client is a combination of a thick and a thin client. Just like the thick client it processes data
internally but relies on the application server for persistent data. Any online gaming run on a system can be
an example of a hybrid client.
What is a Server?
Page | 7
A server is a system or a computer program that acts as the data provider. It may provide data through LAN(Local
Area Network) or WAN(Wide Area Network) using the internet. The functionalities provided by the server are called
services. These services are provided as a response to the request made by the clients. Some of the common servers
are-
• Database Server - used to maintain and share the database over a network.
• Application Server - used to host applications inside a web browser allowing to use them without installation
locally.
• Web Server - used to host web pages because of which worldwide web is possible.
• File Server - used for sharing files and folders over a network.
These clients and servers do not necessarily be at the same location. They could either be located in different
locations or may reside as different processes on the same computer. They are connected via the Web and interact
via the HTTP protocol which will be discussed later in this article. There may be multiple clients requesting a server
and alternatively, a client can request from multiple servers.
As shown in the diagram, a single server may serve the requests of multiple clients. Similarly, a client may be
requesting data from different servers. For example, consider an example of Google. Here, Google acts as the server
and the users sitting at different places act as the clients.
Another example that we come across in our everyday life is the Online Banking Portal in which the browser that we
use to open a portal acts as the client while the database and the software for banking act as the server. This
propagates resource sharing across multiple users and thereby results in cost-efficiency along with time saving.
In the next section let us see how the client-server model works and how does this interaction takes place.
As already discussed above, the client server model acts like a consumer-server relationship. But how does it work?
Let us see some of the flow of information in a client-server architecture through a series of steps as discussed
below-
1. The HTTP communication protocol helps establish the connection between the client and the server.
Page | 8
2. The client sends a request in the form of an XML or a JSON over the active connection. The client and server
both understand the message format.
3. Upon receiving the client request, the server searches the requested data and sends back the relevant details
as a response in the same format in which the request was received.
The above diagram shows the communication process between the client and the server. The client sends an HTTP
request, for which the server sends an HTTP response. Let us consider an example to understand more about it.
Assume that you need to go shopping from your home to a shop across the road. You may travel on a bicycle and on
reaching can order the salesman the goods you need. Now if the salesman finds the goods, he will bring them to you
else he would let you know about their unavailability.
Now, you may link the above example with the navigation to a website, the street between your home and the shop
is the internet connection. The mode of transport that you chose to travel is the TCP/IP, defining the communication
protocol for the data to travel through the internet. The address of the shop is the DNS(Domain Name Server) of the
website. Your communication language with the salesman is the HTTP(Hypertext Transfer Protocol) which defines
the language for interaction between the client and the server. Your order request is the HTTP request and the
update on item availability is the HTTP response.
When the web browser sends a request to the server with the DNS of the website, and the server approves the
client request, it sends a 200 OK success message. This message means that the server has located the website and it
sends back the website files in small chunks of data to the browser. The browser then collects and assembles these
small chunks to form the complete website and displays it to us.
We will discuss more on the HTTP request and response in the next articles.
• Accessing the data from a single server help in cost-efficiency with less maintenance.
• The capacity of the client and the server can be individually modified.
Page | 9
• Due to vulnerability to different kinds of attacks, it requires a special and secure network operating system.
• Possibility of loss of data packets either completely or modification because of some intrusion during the
transmission.
As already understood in the client-architecture model, the client sends the request to the server to fetch some
information or data. Additionally, the client's request is an HTTP Request, which communicates between the client
and the server, or you may say, two different computer systems. Moreover, it is a simple text file formatted in
either XML or JSON, which sends the client's binary data to the server. A simple GET HTTP request looks like below-
https://bookstore.toolsqa.com/BookStore/v1/Books
HTTP request methods specify the action to perform through the request. These are also known as verbs and
generally used for CRUD operations, i.e., Create, Read, Update & Delete. Moreover, HTTP request methods are case-
sensitive and should always be uppercase. Subsequently, let us see some commonly used HTTP methods:
1. GET - As the name suggests, the Get method fetches the information from the server. Moreover, it is the most
commonly used method which does not have a request body. Every time you open a website, the Get request fires to
retrieve the website contents. Additionally, it is equivalent to the read operation. Some of the main features of the
GET method are-
Page | 11
• The limit of the length of values is generally 255 characters for the GET method.
2. HEAD: The Head method is similar to the Get method, but it retrieves only the header data and not the entire
response body. Moreover, we use it when you need to check the document's file size without downloading the
document.
3. POST: The Post method works to send data to the server. You may add or update data using the Post request. We
send the information that needs to update in the request body. In the real world, the form data on website updates
using the Post request. Some of the critical features of a POST method are-
• Data passed through the POST method is not visible in the browser URL.
• Additionally, values passed through POST are not stored in browser history.
• Moreover, there is no restriction on the length of data sent through the POST method.
• Also, POST method request supports different data types like String, binary, integers, etc.
4. PUT: The Put method is similar to the Post method since it updates the data. The only difference is that we use it
when we have to replace an existing entity completely. Also, PUT methods are idempotent, i.e., they return the same
result on executing repeatedly.
5. PATCH: This method is again similar to Post and Put methods, but we use it when we have to update some data
partially. Moreover, unlike the Post and Put methods, you may send only the entity that needs updation in the
request body with the Patch method.
6. DELETE: Like its name, the Delete method deletes the server's representations of resources through the specific
URL. Additionally, just like the Get method, they do not have a request body.
7. OPTIONS: This is not a widely used method when compared to other ones. It returns data specifying the different
methods and the operations supported by the server at the given URL. Moreover, it responds with an Allow header
giving a list of the HTTP methods allowed for the resource.
Let us now see how the structure of a simple HTTP request looks.
The next step is to understand how an HTTP request looks like and how it is structured. An HTTP request consists of-
1. Request Line
Let us now see what these components are, but before doing that, let's see a simple BookStore REST API developed
by ToolsQA.
• Parameter: BookStore/v1/Books
Now you need to open a browser window and hit this URL. Subsequently, you can open the browser developer tools
and navigate the Network tab as highlighted in the image below before you hit the URL.
Once you hit the URL, you will see some requests being sent; you need to click on the first one highlighted below and
see that a detailed request description shows up on the right side.
Conclusively, we are now ready to understand the different components of the HTTP request.
Request Line
Request Line is the very first line in an HTTP request. The combination of three parts forms it-
Looking back at our example, the Request-Line for our case would look like this:
HTTP Method
As discussed above, the HTTP Method specifies the action that should perform through the request. Moreover, the
most common methods that you would come across are GET or POST. Subsequently, we will see the difference
between the two later in this post.
Request URI
Page | 13
The Request URI, i.e., the Uniform Resource Identifier, helps identify the resources on which the request applies.
Request URI has a general format, as shown below.
Let us see some examples of how one can use the above request URI.
1. When we use an asterisk, ',' it implies that the request is going directly to the server and not to a particular
resource. Also, we must use it when the method in the request does not apply to a resource. For example-
OPTIONS * HTTP/1.1
2. Additionally, the abosulteURI form is a must when we make a request to a proxy, which forwards the request
to the valid cache and returns a response. Moreover, an absolute path cannot be empty. If nothing is present,
it should be given as "/ " (the server root) in URI. Example-
3. Moreover, the most common form of the Request-URI is the one that we used in our example. The client
fetches the resource directly from the origin server by creating a TCP connection to port 80 of the host
"bookstore.toolsqa.com", and below lines are sent in request-
The HTTP Protocol version allows the sender to specify the format of the message as well as its ability to understand
further communications. Additionally, HTTP/1.1 is the standardized protocol version that we use commonly.
Request Header
Using the request header, the client can send additional information to the server about the request as well as the
client itself. Additionally, there can be either zero or more headers in the request, which can define the content type,
authorization specification, Cookie information, etc. Moreover, we can also define the custom headers using the x-
syntax as per requirements. The below snapshot shows the different headers for the HTTP Request we are using as
an example. Additionally, the Request Line is also in a highlight.
In the above request, there are some header fields that you will come across quite frequently while testing APIs.
Consequently, let's have a quick look at them-
• User-Agent: lets the server identify the application, operating system, vendor, and version.
• Connection: controls the network connection. In other words, kill or continues the connection after the
transaction.
Other than the above, some of the common request-header fields used as per the requirement are-
• Accept-Charset
• Accept-Encoding
• Authorization
• Content-Length
• Content-Type
• Cookie
• Expect
• From
• Host
• If-Match
• If-Modified-Since
• In-None-Match
• If-Range
• If-Unmodified-Since
• Max-Forwards
• Proxy-Authorization
• Range
• Referer
• TE
Request Body
The request body sends additional information to the server to fetch data from the request correctly. In our
example, we did not send any Request body after the request header, as shown in the snapshot above. Additionally,
the request body may either be in the form of XML or JSON. Subsequently, in the upcoming articles, we will see
these requests in more detail.
The difference between the GET and the POST method is the most common question in the interviews. Let us see
some main points that differentiate both these methods.
GET POST
Data goes through the header Data flows through the request body
The size of data is limited to 255 characters No limit on the size of data
Page | 15
GET POST
Better in performance as compared to POST Less efficient in performance as compared to GET as we spend
since the values append to the URL by default some time on including request body values in the POST request
Parameters get stored in browser history Parameters don't get stored in browser history
No impact on data if we hit the reload button. The form data reset if we hit the reload button.
An HTTP response object typically represents the HTTP packet (response packet) sent back by Web Service Server in
response to a client request. An HTTP Response contains:
1. A status.
2. Collection of Headers.
3. A Body.
So when we say we need to validate HTTP response status, we are looking forward to having a mechanism to read
and validate the entire response object including the status, headers, and the body. Hence, we will validate each of
the HTTP response components separately. So in this article, the validation of an HTTP response status will be dealt
with in three parts as follows:
Page | 16
As we already know the same REST API returns a response message in XML or JSON format. This format depends on
the Media-Type attribute in the HTTP request.
But then how will the client know what type of response it will get from the API? Well, this is managed by the
response headers. Response Header contains a Content-Type attribute that informs about the type of response
body format.
Consider the Swagger UI example we discussed in earlier articles. Suppose we send a GET request to the Book Store
through our browser as follows:
When the above command executes we obtain the response shown in below screen:
As seen from the above screenshot, the response has a status, headers, and a body. If we check the "Response
headers" section, in the above screen, it has a content-type attribute that has the value along with other attributes.
On validating this header, the client knows what type of response (body) we can expect.
Let us now proceed with validating the status part of the response.
When the client requests a piece of particular information from the server, the server sends a response with a status
code back to the client. The status code that the server returns tells us whether the request was successful or not. If
the request was successful, the server sends the status code in the range of 200-299. If the request was not
successful, then the status code other than the range is returned. We can get the list of HTTP status codes along with
their description on the W3 page.
Rest Assured library provides a package named "io.restassured.response" which has a Response interface. The
Response interface provides methods that can help to get parts of the received response. The following screenshot
shows some of the important methods of the response interface.
Page | 17
The method *getStatusCode() is used to get the status code of the response. This method returns an integer and
then we can verify its value. TestNG Assert* is used to verify the Status Code. Now consider the code given below:
java import static org.junit.Assert.*; import org.testng.Assert; //used to validate response status import
org.testng.annotations.Test; import io.restassured.RestAssured; import io.restassured.response.Response; import
io.restassured.specification.RequestSpecification;
// Get the RequestSpecification of the request to be sent to the server RequestSpecification httpRequest =
RestAssured.given();
The below line of code extracts the status code from the message:
The return value "statusCode" is compared with the expected value i.e. 200. If both values are equal, then an
appropriate message is returned.
Page | 18
java // Assert that correct status code is returned. Assert.assertEquals(statusCode /actual value/, 200 /expected
value/, "Correct status code returned");
If you run the above test, you will see that the test passes since the web service returns the status code as 200 as
shown in the below image.
In this manner, we can verify the status code of the response using the "getStatusCode()" method of the response
interface. Please note that since we already knew that the success code here is 200, we wrote the appropriate code.
Your server may respond as success with a code anywhere between 200 and 299. It is best to check that out
beforehand. Let us now move on to discuss how to validate the status code that returns values other than 200 i.e.
error status code.
So far the request-response situations are all good and we have only received 200 status codes indicating successful
requests. But this may not be always true in the real world. There can be reasons like the server is down or REST API
not functioning properly or the requests themselves may be problematic. In conclusion, we may face the following
scenarios:
4. An error occurs on the server side during the processing of the request.
So when any of the above scenarios occur, the REST API will return an appropriate status code other than 200. The
client in turn has to validate this status code and process it accordingly.
For the ToolsQA Book Store service, let’s create another test with an erroneous scenario. Here we will validate the
HTTP status code returned by Book store Web Service when an invalid parameter is entered.
So here we provide the parameter to get user details. Here we provide nonexistent userId as the parameter. The
code looks as below:
java import static org.junit.Assert.*; import org.testng.Assert; //used to validate response status import
org.testng.annotations.Test; import io.restassured.RestAssured; import io.restassured.response.Response; import
io.restassured.specification.RequestSpecification;
@Test
RestAssured.baseURI = "https://demoqa.com/Account/v1/User/";
Page | 19
RequestSpecification httpRequest = RestAssured.given();
When we run this test it returns the error code of 401. We can see the result of the test execution below.
Note: We can make a quick change to the code above to make sure the test passes. This change is shown below:
java Assert.assertEquals(statusCode /actual value/, 401 /expected value/, "Correct status code returned");
So here we expect the value returned to be 401 instead of 200, hence the test is passed. Next, we will validate
the "Status line".
A "Status-Line" is the first line returned in the HTTP response. The status line consists of three substrings:
• Status Code.
For example, when the request is successful the status line will have the value "HTTP/1.1 200 OK". Here, the first
part is the HTTP protocol (HTTP/1.1). Next is the HTTP status code (200). The third is the status message (OK).
We can read the entire status line using the method getStatusLine () of the response interface. The following code
shows the demonstration.
// Get the status line from the Response in a variable called statusLine
Here we perform a similar test as we have done for the status code. We read the status line using the getStatusLine
() method into a string value. Then we compare this returned value with "HTTP/1.1 200 OK" to check if the status is
successful.
Note: The postman article on the same topic (Response in Postman) can be found at Response in Postman.
You asked me the links for the books honey do u remember? At this link you will learn postman in these sections OK?
This tutorial is completely designed for you to understand Postman even though you have never heard of Postman
or let's say API. Since Postman is an API testing tool, we must know what is an API. So in this tutorial, we will explore
the different topics around API such as
• What is an API
• API Testing
Starting with the first, we will start our journey now by learning about APIs.
What is an API?
API stands for Application Programming Interface. Talking in technical terms an API is a set of procedures, functions,
and other points of access that an application, an operating system, a library, etc., makes available to programmers
in order to allow it to interact with other software. Didn't get it? Well, neither did I. Let's break these terms and
explore more about APIs.
Taking an analogy here, let say you went to a restaurant. There is no waiter present, so you need to see the menu
lying on the table and then make a request to the kitchen where the chef will prepare the dish for you. But it does not
always work that way. What if the dish is not available? You will have to go to your seat again and decide something
else. There will be many customers present in the restaurant which will slow the process of the chef since now he will
be listening to the orders instead of preparing them. Also, how can we forget we live in this multilingual world? What
if you do not understand the chef's language? We need a waiter here. A waiter is what can be seen as an API in the
internet world. The waiter will come and take your requests, give them to the chef, and then in response bring back
the food. This waiter is bilingual and speaks both of your (chef and you) languages fluently. What if the dish is not
available? Well, the waiter knows beforehand you made the wrong request, so he will tell you then and there on the
table that the food item is not available. How much time and energy is saved? This is exactly what an API does.
Page | 21
As we visually depict the above analogy using an image, we can see that you are working as a user in the API world.
You make the requests while the waiter works as an API who is an intermediary and takes the request to the
appropriate server. This server will be processing your request and responding back to you. As said above, your
server or application is the chef who is in the kitchen. He will process your request, cook your desired food and
present it back to you as a response. The methods and parameters will be discussed in detail later but here in the
analogy, you can think of it as the special requests you make according to your taste and liking. For example, you
order something from the menu and describe explicitly that it should be extra spicy. This will help the chef to cook
according to your demands.
Page | 22
An API takes your requests from the device and fetches the response from the server. Today, API is everywhere. We
have achieved so much through APIs, it's hard to count. If you are into computer science or IT industry, there is no
escape from APIs. APIs help you fetch a particular response according to the particular request. For example, while
you are booking a flight, you will require specific flight results according to the source, destination and departure
date, and maybe some other variables. For this, you might have to visit different airlines to check their different
price. But through APIs, this is not so difficult. Through different APIs of different airlines, we can get the response of
each and every airline for that specific query at one place like GoIbibo does. Maybe now you must have got the idea
of how vastly APIs are used today. We all are connected through APIs. All the services that are offered online are
mostly through API. As I said, APIs are everywhere
API Testing
So now that we have established what an API is and why APIs are critical to modern interconnected, globally
distributed applications and services, it is important to understand why API testing is critical.
API testing creates a more reliable code. But historically, testing would take place at the GUI level. When a developer
would finish their work, they would hand it off to the QA engineer. The engineers had limited time so they would
test the code at the highest level - the GUI. This would cover both the front-end and the back-end development.
This worked for manual testing and for the beginning of automation testing but isn’t right for the age of agile and
continuous testing. GUI testing is too brittle, GUI automated scripts break easily and are more time-consuming. But
more importantly, when the application is underdeveloped, teams can’t wait for the entire system to be updated
and the GUI to be ready before testing occurs.
In the age of agile, testing must take place at a lower level, i.e at the API level as early as possible. Developers can
even do it themselves. API's can be tested even when the GUI of the application is not yet ready. On top of that API
tests, because of “API contracts”, can even be created before development is complete.
An API or rather all the API present in the software/application should be tested perfectly. This is the job of a
software tester and bears a huge responsibility. A perfect working API leads to the perfect working application.
Testing the API solves a lot of issues in the application which may arise at some point of time in the future. There are
much software available for API Testing and one such software is Postman.
As an API tester, you should have good architectural knowledge of various web services, REST, SOAP and Micro
Services.
1. Should able to use all the web methods like GET, POST, DELETE, etc
3. Able to validate the XML and JSON body by using Json parsers
Page | 23
7. Able to derive a good number of test cases and scenarios.
9. Become master in a tool of your own choice SOAP UI and Postman are not Automation tools. Rest Assured,
Rest Sharp, Node modules are the open source libraries for API testing.
API testing and unit testing are considered the same thing by some testers but actually, it is different. Unit testing is
done by the Developers or by Test Engineers and is done on a class by class basis or on the single component
level. Motive is to verify whether the module delivers the required functionality. The development team monitors
unit testing activity and makes necessary changes wherever required. A major emphasis is on the fact whether each
unit or module works perfectly fine in isolation. That is, dependency should be least to ensure a robust module
design.
On the other hand, API testing is basically black box testing which is simply concerned with the final output of
the system under test. API tests are executed only after the build is ready and portray the system as a whole as it is
the user interface that an end user will interact with.
API testing primarily aims to test the business logic layer of the system's architecture. API testing is primarily handled
by the QA team, which requires them to run any API on top of a particular build meant to serve a specific purpose.
API testing also tests the unit as part of a system, while unit testing typically tests the unit in relative isolation
from the rest of the system. Hence API testing is also end to end testing. This simply means when we test the
complete software in API testing then the modules which make that software are also tested, obviously. But when
we do unit testing, we focus only on the functionality of that module and see its working which is completely
isolated from the rest of the modules/software.
When we test any API through a tool, we face a lot of errors normally. These errors are not only related to only APIs
but can vary from software error to server error. This makes the job of a software tester more important and wide
than it seems. Since a software is built and delivered in steps, same goes for testing it. When a software is in
development stage, the tests and cases are built accordingly. This helps the developers to see any errors of server or
network etc. Same goes for any other stage of software such as production stage in which you evolve and upgrade
those tests cases. The area for covering your tests should be as wide as possible. It should cover every little
possibility of the failure so that the software is built of premium quality and feedback team receives minimum
tickets.
With this section, we conclude this tutorial here. Next in this course we will introduce you to the software postman
and will download it on our systems. I hope you will enjoy this course with me.
Page | 24
Download Postman and Install On Windows and MacOS
Download and Install Postman
Since you now know about the application and have become familiar with its working, it's time to install the
application on your system. In this chapter, we will cover How to Download and Install Postman on Windows
Machine.
Postman is available for Windows, Linux, and Mac as a standalone application. You can install the application in two
ways.
• As a Standalone Application.
• As a Chrome Extension
You may also go through the recording of the Postman Tutorial where our experts have explained the concepts in
depth.
A native application means the application will not be supportive of any particular application on an operating
system. For example if you install an extension from chrome webstore then that application or extension will only run
on chrome and no other browser. A native application is like any software that you install like a game or IDM or any
antivirus for instance. A native application takes the support of just your operating system and not another
application because they are written system specific and not application specific.
1.Go to https://www.getpostman.com/apps
Note: If you are using windows then there is an option for downloading for 32-bit system and 64-bit system. If you
are using 64-bit windows then select x64 and if you are using a 32-bit system then select x86. The default value is
x64.
2. Choose the Operating System on which you want to download PostMan and click on "Download" button.
Since I have got Windows 64-bit machine, I am going to install x64-Windows.
Page | 25
3. Once you download the .exe file, you will need to install the application. Since I am using the Chrome browser, the
downloaded .exe will appear at the bottom left of the browser.
3. Click on the exe file to install it on the system. First, it will install the POSTMAN application.
Page | 26
4. There are no further steps for installing. After completion, it will automatically start opening the PostMan
tool.
5. Once you have the application window up, click on Take me straight to the app. I'll create an account
another time as highlighted. Alternatively, you can sign up with google but it does not matter at present.
If you see this page then you have successfully installed Postman on your system.
Page | 27
Download POSTMAN as a Chrome Extension
Page | 28
3. Now it will automatically open a Chrome Apps page, where it will display all the installed apps on your
chrome browser. Simply click on the PostMan application.
5. Once done, you would see the PostMan application registration page. As mentioned above, we will ignore
registration as of now but not to avoid it, *Registration has its own benefits, as it always stores your data
and can be accessed from different machines and locations. *But we will cover that later.
Page | 29
Why to prefer PostMan as a Stand Alone application
Although Postman was introduced first as a chrome application and was powerful earlier on, we highly recommend
downloading postman as an application for your operative system(native application) rather than as an extension for
chrome.
• First of all, postman as an application for chrome does not support all the features that the native app has.
For example, a proxy cannot be captured in the chrome app. You need to install another extension
called postman interceptor in order to work the proxy through the browser. A proxy server acts as an
intermediary that captures the requests that you send through your browser to the server. Requests are
anything like any web address any search query or anything that asks for a response from server. For
example, when you hit "Search" in google after writing something in the search bar, it is an API request or
you type www.google.co.in in the address bar, it is an API request. After installing the postman interceptor
only you can capture the requests that you send. Moreover, Postman features fewer menu options in its
chrome app, only those which adhere to the chrome standards. Therefore you won't be able to enjoy every
feature of Postman while using it as a chrome application.
• The second reason is the main concern for us to not recommend you, download postman, for chrome. As
stated on the Postman website, Postman builders have stopped the support for the chrome application. This
in simple terms means that from January 2018 onwards, there will be no updates, no bug fixes, no
improvements in the chrome application. The app that is currently available on the web-store is the final
application. Moreover, if you are stuck on any issue, there will be no one to resolve it from Postman. This step
Page | 30
is taken by Postman after Google announced that it will be ending support for the Chrome apps for Windows,
Linux and Mac.
As it can be seen in the below image taken from the postman website, the last update for the Chrome app was on 18
Oct, 2017. So, it is better that you install the Standalone application and the same will be used by us for this course.
In the next chapter, we will run through some basics and terminologies about the Postman.
Postman Navigation
Postman Navigation
Now that we have installed Postman on our system, we will navigate through the UI of Postman in this Chapter. We
will become familiar with the terminologies and features that Postman offers.
Page | 31
You may also go through the recording of the Postman Tutorial where our experts have explained the concepts in
depth.
1. Sidebar section
• History
• Collections
2. Header section
• New
• Import
• Interceptor
• Sync
3. Builder section: These items will help users to create a new Request. We will learn about these items in detail
in the coming chapters
• Tabs
• URL bar
• Header's list
4. Response section: It is filled only when invoking a REST request. This section will be populated with the
details of the received Response. We will learn more about it in the coming chapters. Now let us see
individual sections in detail.
The sidebar is a very important part of the Postman. The sidebar has two main parts or tabs which
are History and Collections.
Page | 32
History Tab
Postman records a history of your API request just like any other web browser automatically. As soon as you invoke a
REST request, it is saved in the history and can be seen below the History Tab. It comes in handy when you have to
search for some particular request that you entered in the past without entering again.
Collections
The concept of grouping requests is called Collections and each Collection is displayed under the Collection Tab. As
shown in the image below. A collection in Postman can be imagined similar to a folder in your system. You create a
folder, for example, movies, and keep movies in it so that you know where all your movies are. Similarly in Postman,
we save the similar kind of requests under some collection name (that we define) and when we open any collection
we get all the Requests under that heading, As shown in the below image
The below image shows just the Header of the Postman application.
New
Page | 33
Choosing this option will let you choose what "new" you want to start. For example, a collection would open the
panel where you can enter a new collection to start and its corresponding requests. Selecting "request" in New will
open the request panel where you can enter and save the requests into the collection of your choice. A new option
lets you create the following:
• Request
• Collection
• Environment
• Documentation
• Mock Server
• Monitor
Import
Import option lets you import files of different formats. Importing means choosing the files located in your system or
through a link and running it through Postman. As can be seen from the image it allows you to import a Postman
Collection, Environment, Curl command, etc. Importing a collection is the most common among all.
Interceptor
Page | 34
Recall we learned that if you are installing the application from chrome then a separate interceptor is required for
the proxy server. This interceptor is inbuilt in the native app. You can set a proxy server here to capture all the API
requests that you send through your browser. A proxy server can be used to capture all the requests that you send
through your browser or from your phone or any other system.
Sync
Sync option is for synchronizing the API requests that you have sent on any machine to the Postman cloud. When
you are working in Postman and making changes or sending requests, if you Sync is on, it will automatically be saved
in your Postman's cloud storage. This way you can have them saved and whenever you sign in on a different
machine to use Postman, they will automatically appear. This feature requires you to sign in (If you did not during
the installation part).
A builder part of the Postman is basically what a CPU is to a computer. It is the main part that controls all the
functionalities and methods to be incorporated inside the API.
• Request Type:
• Params: This option let the user define different Query Parameters for the request.
Request Type
This is the request type method for the API. It indicates the type of HTTP Request that has been sent. There are
different kinds of requests which we will discuss as we proceed further, but just to know, there are four main types
of requests namely GET, POST. PUT and DELETE.
This is the box, besides the request type option, to enter the EndPoint (API). It acts just like a browser with a similar
interface for the New tab. We enter our required endpoint into the bar which is our main URL.
Params
Params are the parameter option that allows us to write the parameters of the URL. The parameters are embedded
into a URL and are very important to get the desired result. They also help us in getting efficient usage of the
memory and bandwidth. This will be discussed in a complete chapter later on.
Authorization
Page | 35
The authorization process verifies whether you have permission to access the data you want from the server. Not all
data is available for everyone inside a company, so there lies the solution as Authorization. With the authorization,
the server first checks whether the data you are asking for can be shown to you. If it can be, you get the desired
response.
Header
A header in the HTTP request or response is the additional information that is needed to be conveyed between the
client-server. HTTP headers are mainly intended for the communication between the server and client in both
directions.
A response box is a box that shows the response from the server that we receive after requesting through API. A
response box has many options in it, which won't be feasible to explain here in this chapter. In the coming chapters
you will learn about the response, although if you want you can visit the chapter here.
Now, since we have installed Postman and have become familiar with the interface, it's time to start our first steps
on Postman for which Postman is actually used for. To start with this tutorial, we will start with the Header part of
the Postman and follow the steps.
You may also go through the recording of the Postman Tutorial where our experts have explained the concepts in
depth.
Page | 36
2. Click on Request.
3. Enter a meaningful Request Name, like First Api we are using. You can also use the description about the API
to remember later about what that API did for other teammates and yourself, but it's optional and we won't
be using that in this tutorial.
Page | 37
4. Enter a meaningful Collection name in the bottom panel, like First Collec we are using, and select +Create
Collection as shown. Press Save.
5. Select Collections tab in the sidebar, then you will notice all the collections folders, select First Collec and
then select First Api under the First Collec tab.
7. Press Save if you wish to overwrite "First Api" or press the dropdown as shown and Save as a new request.
Page | 38
The Save As option opens the same panel which opened through New Request at the start of this tutorial. It gives
the option to enter the name and associate the request to some collection.
This way you have created a Request and saved it under the desired collection. In the next tutorial, we will send our
first GET request.
Assuming you are now familiar with the HTTP protocols and architecture, we will now talk about one specific type of
request which is a GET request. A GET request is used to get the information from the server and does not have any
side effects on the server. Side-effects mean there is no updation/deletion/addition of data on the server when you
are making this type of request, you just request from the server and the server responds to the request.
A GET request has all its information inside the URL, and since URL is visible all the time, it is advisable not to use this
type of request while you send some sensitive information such as passwords. For example, when you press search
after writing anything in the search box of google.com, you actually go for a GET request because there is no sensitive
information and you are just requesting the page with search results, you notice the same search string in URL.
You may also go through the recording of the Postman Tutorial where our experts have explained the concepts in
depth.
In this image, as you can see, there is a drop-down button which has different types of request types according to
the API need. As of now do not worry about all of these different HTTP Requests, as we will cover each of these in
this Postman Tutorial series. But for now, just focus on the GET Request.
2. Enter www.google.com in the address bar as written in the above image and Press Send. Now, look at
the Status Code.
Page | 39
Different status codes have different meanings and it does not matter whether it is a GEt request or any other type
of request. In this scenario, we have status code 200 OK which means that EndPoint is correct and it has returned
the desired results. We will show some more status codes later.
The colorful text inside the box below is the Response from the server. If you observe closely inside the response box
you will see the page code has been sent to us. The above tab says Body. Body means you have selected to view the
response body which is been shown inside the box. In Body, you will see three options.
• Pretty: In this code will be shown in a colorful manner with different keywords colored differently and will be
indented for some of the formats for good reading.
• Preview: This shows the preview of the page that has been sent. Don't worry about the google doodle if it
has not been loaded properly. Try any other website by yourself.
A response is a more detailed topic than it needs to be explained in this chapter. We will be explaining the response
completely in the next chapter.
Response in Postman
In the last tutorial we learnt about Get Request in Postman. In this tutorial we will understand how to deal
with Response in Postman. It will be beneficial if you understand the underlying details of an HTTP Request and
an HTTP Response.
What is Response?
A Response is a message that is received by the server in return to a Request that we send. When we request
something, the server acts upon the Request and sends back a packet of the requested information. A response
depends on the request mainly. Every request has a different kind of response and it is very important that we
extract useful information from all of the responses. Postman has a beautiful interface for response and is very user-
friendly. We can see a lot of information in the Postman for any response without doing much effort, or any if I
might say.
Page | 40
You may also go through the recording of the Postman Tutorial where our experts have explained the concepts in
depth.
Talking about Response in Postman, the Response user interface contains lots of different things. We will deal with
them in detail in this tutorial. The user interface has the following information blocks
• Response Body
• Response Cookies
• Response Header
Let's start by getting a response for www.google.com which looks like this:
Status Code :
A status code tells you the status of the request. There can be a lot of mistakes in the request and without looking at
the status code, we might not always get what went wrong to our request. Sometimes, there can be a typing mistake
in the URL or there can be a problem at the server-side, status code help us know about what went wrong (if
something went wrong). There are different status codes and each of them has a different meaning.
You can learn about the complete list of status code here.
Status code 200 OK means that the request was correct and the desired response has been sent to the client. Now,
change the URL to http://restapi.demoqa.com/utilities/weatherfull/city/hyderabd . Press Send and see the status
code now.
Page | 41
It says 400 BAD REQUEST. It is so because we have changed the name of the city from Hyderabad to Hyderabad.
This means the request was not correct, hence the bad request response. Similarly, you can see other status codes
also for different requests.
Time
Time is the duration which the response took after we sent the request and received the response. This is very
important sometimes because many projects have Service Level Agreements(SLA) for the time it should take a web
service to return a response, this time can be a used to determine the SLA of the web service endpoint.
NOTE: The time given here is not the actual time that the request will take. It is just approximate but almost what it
would be because there are a lot of things that Postman do after getting a response such as formatting and dividing
Headers and cookies separately. As the additional work by Postman can be roughly considered as a constant time
(WebServiceTime + Constant processing time by Postman). Therefore, it is an approximate of the time and is
proportional to what the actual time will be. So you can consider this as actual time as well.
Size
Size is just the response size when it will be saved inside the memory. This response size is the size of complete
response and headers and cookies and everything that has been sent along with the response.
NOTE: The response size that is shown in the Postman is approximate response size and not the exact size.
Response Body
A body depicts the body of the response, which is the main response content, that has been sent from the server. In
this case as you can see it is a web page code being sent to us as a response. Now, there lie three ways ahead of us
to look at this response:
Pretty
Pretty is a prettier version of the content being sent. The content is prettier as it is more readable. It has coloured
keywords and different colours have different meanings. This makes a code more readable and look nicer. This
formatting is done by Postman itself after getting the code.
Raw
Page | 42
Once you click on Preview you will get just the plain view of the content, as received from the server. It is just a raw
version of the code without any colorful keywords. By looking at this code you might get why the other code is called
"Pretty".
Preview
Preview of the code will show you the preview of the page, had the page been run inside a browser. Click on preview
and you will see the exact page as you would have seen inside a browser. So this would let you know the response
preview without visiting the browser.
Format Type
As discussed above, a request has a defined response to it as defined by the Content-Type header. That response
can be in any format. For example, in this case we have the response as a HTML code file.
Postman is smart enough to detect the response type and show you in the desired format, but sometimes Postman
can also make a mistake. For example, use http://restapi.demoqa.com/utilities/weatherfull/city/hyderabad to get
a response.
You will see that we have received a status code 200 and still there is no response. This is because Postman has
failed to recognize the format of the response and is expecting a HTML file as seen in the dropdown.
Select Text in dropdown and you will be able to see the response now.
Page | 43
Sometimes, the server sends the response in two or more different formats. The type of response will be visible to
its corresponding format type.
Note: Content-Type header defines the format of the response. For e.g. the Content-Type header may say that the
response is JSON, however, the content being sent is XML or a malformed JSON. In that case Postman will not be able
to do much. Take it as an exercise to understand why Postman is not able to understand the format of response
returned by http://restapi.demoqa.com/utilities/weatherfull/city/hyderabad
Copy Response
The icon with two rectangles that you see in the corner is used for copying the complete response to the clipboard
which is very handy to send the response to your teammates or using afterwards.
Cookie
Cookies are the small files which are related to the server files (website pages). Once you visit a website for the first
time, a cookie is downloaded on the client's machine. This cookie contains the information which can be used by the
same website when you visit again. This helps the website to get you the specific response and specific information
based on your last visit. In postman we can clearly see the cookies that have been sent from the server as a
response. This makes it easy for the client to see what cookies are being saved inside his browser. We cannot
manipulate this cookies since they are sent from server, Postman is used just to separate it from the response and
have a clear view.
Header
Headers in an HTTP request or response is the additional information that is transferred to the user or the server. In
postman, the headers can be seen in the Headers tab.
Page | 44
Once you click on header you can see different information such as below. Although, every entry in the Headers tab
is a header item we will just take a look at the most important ones.
• Content-Type : This is the content type of the response. In the above example when we used
www.google.com the content type is given as text/HTML because the response is being sent in the HTML
which is one of the options.
• Date : This option shows the date, day and time of the response along with the time zone.
• Server : This option tells the name of the server which has responded to the request. In the above example,
the server name is shown as gws which corresponds to Google Web Server.
• Cookie expire time : As the name suggests, this option tells the expire time of the cookie that has been sent
along with the response.
Request Parameters are part of the URL which is used to send additional data to the Server. Let us analyze a simple
URL:
https://www.bing.com/search?q=ToolsQA
In this URL Request parameter is represented by the "q=ToolsQA" part of the URL. Request parameter starts with a
question mark (?). Request parameters follow "Key=Value" data format. In our example "q" is the Key
and "ToolsQA" is the value. The server reads the Request parameter from the URL and sends a Response based on
the Request Parameter. In our example, Bing will return search results for ToolsQA. If you change the Value
from ToolsQA to DemoQA, you will get results for DemoQA instead of ToolsQA. This means that the Server reads the
Request parameter and responds based on that.
In simpler words, let us say I designed a page that can show you the student list of a particular class. Now, the list will
depend on the class you select, which will be passed in the URL as a parameter while the page I designed will be the
same for every class. I don't have to design many pages as many as there are classes. This way we improve the
efficiency and usage at both levels.
Parameters can be passed in GET Request, if you are not sure how to do a GET Request using Postman, please take a
look at the previous article How to make a GET Request. Since now you know how to make a GET request, we will
move ahead with sending parameters in a GET request.
You may also go through the recording of the Postman Tutorial where our experts have explained the concepts in
depth.
Page | 45
Before talking about Parameters and understanding them clearly, we will send the URL to our browser.
2. You will see the response page from Google. Type ToolsQA in the search bar and press Google Search.
Now you need to understand here that the page which shows the results will remain the same just the results will
differ according to the search. You just now searched for ToolsQA, this serves as a parameter in the URL to tell the
server that we need the results of the ToolsQA specifically. The server responds according to the search parameter.
A URL consists of many parameters such as source id and encoding format etc. See the URL below and you will
see &q=ToolsQA which is added in the URL to tell the server.
Page | 46
Note: here "q" is the key represents query and ToolsQA is the value of the key or search term for the query.
1.Just prepare a GET Request in Postman with the URL www.google.com/search and then click on Params.
2. Write the following things written under Key-Value pair as shown. Again q stands for query here and
ToolsQA is the search term. Now press Send.
3. Look at the preview, you would see that instead of the google home page we have received a response for a
specific search query which is ToolsQA. Instead of ToolsQA you could write anything and receive its
response. This indicates that we have passed some information (Parameters) about the result we wish to
see.
NOTE: As discussed above, you can see that different search queries give different results but the page design
remains the same, just the content differs.
Multiple Parameters
You can also use multiple parameters inside a single query. As we discussed above while sending the search query
as ToolsQA, there are many parameters that are sent in the URL. ToolsQA was for the results that were to be shown,
Page | 47
another parameter such as encoding format is also used to tell the server in which format can the result be encoded
and sent to the client. In the above example, the default encoding format used is UTF-8.
See the above image and focus on just the URL sent to the server
In the above URL wherever you see & it must be succeeded by a parameter such as &ie=UTF-8 means ie is a key
parameter with a value UTF-8. You can write each of the parameters that you see above in the postman and send a
request with multiple parameters.
These parameters are not for our users to study in detail. Even if you change the parameters, the changes reflected
will not be seen on the page and you will still get the same response as before because all these parameters are for
internal activities in the server such as logging the submission.
If you are wondering how to separate a given complete URL with its parameters to use in Postman then Postman has
it sorted out for you. You do not need to worry about the parameters in a URL. You can simply paste the URL and
Postman will fill the parameters itself.
For example, copy and paste this URL inside your postman like shown
below https://www.google.co.in/search?q=toolsqa&oq=toolsqa&aqs=chrome..69i57j69i60l5.2885j0j4&sourceid=c
hrome&ie=UTF-8
Now click on Params and you can see that everything is sorted out itself and the parameters are as in the above
image (more or less).
Another interesting feature about Params is that Postman removes the headache of remembering and entering the
same parameters again and again to every query, instead it lets you enter once and forget about entering the same
Page | 48
parameters again. For example, let's say you have to run the same query that we just run but with a few fewer
parameters. For achieving the same,
1. Click on Bulk Edit, you will see the list of all parameters
2. Copy everything
3. Open a new tab and write your URL which is www.google.com/search in this case
5. Paste everything you copied in the editor and click on Key-Value edit
Here you will see every parameter has been adjusted automatically to the new request.
Page | 49
This makes Postman really very efficient while using the parameter option and leaves us out of the context of its
complexity. A parameter is a very important part of a URL and readers are recommended to observe the different
parameters in a URL for better learning and understanding, whereas this was all about parameters usage inside
Postman. Next, we will see about the response in Postman.
In the previous tutorials, we have learned about how to send a GET Request and we also learned about the Request
Parameters. From our Rest basics we already know what an HTTP Request and HTTP Response is.If you have not
read these two tutorials yet, please do that before proceeding. In this chapter, we will focus on another type of
request method which is POST Request in Postman.
A POST is an HTTP Verb similar to a GET request, this specifies that a client is posting data on the given Endpoint.
A POST request is a method that is used when we need to send some additional information inside the body of the
request to the server. When we send a POST request we generally intend to have some modification at the server
such as updation, deletion, or addition. One of the classic example of a POST request is the Login page. When you
first Sign Up for anything, let's say Facebook, you send your personal information such as a password to the
server. The server creates a new account with the same details and that account is added permanently on the
Facebook server. You just created a new resource on to the server. POST requests are very popular and are mostly
used whenever you are sending some sensitive information such as submitting a form or sending sensitive
information to the server.
In this tutorial, we will explore different features of POST Requests and how we can create them in Postman. Before
we will try to use an example to get a clear idea about a POST Request.
Every REST endpoint has its own HTTP verb associated with it. If an endpoint specifies that it should be called using
the POST HTTP verb, then clients are bound to call the Endpoint with POST HTTP verb only. Let's first check what
happens when we request the GET method instead of the POST method for a POST Endpoint. Also to check what
happens when we do POST Request without Body.
1. Use the API http://restapi.demoqa.com/customer/register (This API is used for registering a new
customer) in the Postman endpoint bar and press Send. Make sure that GET is selected in the Method type
dropdown.
Page | 50
2. See the HTTP status code, it will be 405 Method not allowed. Which means that we are hitting the endpoint
with incorrect method type. The below image shows the details.
3. See the response below under the Body tab and focus on fault error.
It means that the method type we used is not valid and another method type is expected. So we will try to change
that and see if we get the correct response.
Page | 51
2. Now, look at the Response Body and Response Status code.
Fault Invalid Post Request means that the post data that we entered is not valid. Recall that we add the information
inside the body of the request, so we need to enter something into the request body and see if that format matches
the format expected. Also, you can see the status code which says 400 BAD Request. It means that the request
parameters are not matching the server parameters to get a response.
1. Now let us add a Request Body to our POST request. Every Endpoint will be documented with what kind of
Method type and the format of the body that it expects. Let us see what body this request expects and how
to add it. For that click on the Body tab.
2. Click on raw and select format type as JSON, since we have to send the incorrect format that the server
expects.
Page | 52
3. This endpoint expects a Json body which contains the details of the new user. Below is a sample Json body.
Copy and Paste the following in the body tab of Postman.
* “FirstName”: “value”*
* “LastName : “value”,*
“UserName : “value”,
“Password”: “value”,
“Email”: “Value”
Change the attribute value to any value you want (take reference from the below image).
4. Press Send and see the Response Body and Response Status.
The error Fault User Already Exits means that in the database, a similar entry has already been created by you or
anyone else earlier. Whereas if you see that the Response Status is 200 OK, which means that server accepted the
request and sent back a successful response. We can also infer from this that the response body was correct and the
server was able to interpret the response body. Now in this API Request, Email and Username should be unique. So
you can change those values (anyone will also work).
Page | 53
Operation completed successfully means that your entry has been created successfully in the database.
So, by this example, it is clear that whenever we need to send a POST request, it should be accompanied by the
Body. The body should be in the correct format and with the correct keys to get a correct response from the server.
Now, we will learn in detail about every feature of Post request in Postman.
As we discussed earlier, sending a POST request means sending a request with the data wrapped inside the body of
the request. There can be different types of data and similarly, there are different ways of sending data. As you will
follow these steps, you will learn in detail about it.
As soon as you select the POST request type in Postman you will see that the option Body is enabled which has
different options to send the data inside the body. These options are:
• Form-data
• X-www-form-urlencoded
• Raw
• Binary
Form Data
Page | 54
Form data as the name suggests is used to send the data that you are wrapping inside the form like the details you
enter when you fill out a form. These details are sent by writing them as KEY-VALUE pairs where the key is the
"name" of the entry you are sending and value is its value. The following steps will make it clear.
1.Select form-data
Here, the first name in the field of some form (text field here) that is needed to be entered and Harish is its value i.e.
the value the user has entered. Similarly goes for Last name id.
x-www-form-urlencoded
Form data and x-www-form-urlencoded are very similar. They both are used for almost the same purposes. But the
difference between the form data and x-www-form-urlencoded is that the URL will be encoded when sent
through x-www-form-urlencoded. Encoded means the data which is sent will be encoded to different characters so
that it is unrecognizable even if it is under attack.
Raw
Raw is the most used part or option while sending the body in the POST method. It is important from the point of
view of Postman. Raw means the body message is shown as a stream of bits representing the request body. These
bits will be interpreted as a string server.
1. Click on the dropdown besides binary and there can be seen all the options in which you can send the
request
2. Click on JSON(application/json)
Page | 55
3. In the editor below copy and paste this
This is the same data that was sent previously with form-data but instead it is now sent with the JSON format.
Binary
Binary is designed to send the information in a format that cannot be entered manually. Since everything in a
computer is converted to binary, we use these options which cannot be written manually such as an image, a file,
etc. To use this option
Note: If you wish to send to the server some data along with the file then it can also be done in the form-data.
Page | 56
Enter file as a key
and you will see a hidden drop-down that says Text as default. You can choose any file format and then select the file
from the system.
Always remember what your server is expecting. You cannot send another format than what your server expects,
otherwise, there will be no response or incorrect response which can obviously be seen by the status code of the
response. So now, we have learned about the POST method and how to use it in Postman. We will move on to the
next tutorial now which is Collections.
What is REST?
The world wide web has become too complex today. With hundreds and thousands of electronic media talking to
each other, the process of communication has become too complex and heavy on computation for sure. Such
scenarios call for something that can ease out the communication and keep the coding complexity to a minimum as
well. That something is the focus of this post and is termed as REST.
REST, or REpresentational State Transfer, is an architectural style and provides standards between the systems on
the web. Popularly, RESTful systems use the REST style to communicate with each other. So in many places, you
might see "RESTful" over the internet and it means the same thing. In this article, we dwell in more details about
REST basics and will cover the following topics in this article.
o Uniform interface
o Client-server separation
o Stateless
o Layered system
o Cacheable
o Code-on-demand
REST (REpresentational State Transfer) was first presented in the year 2000 by Roy Fielding as an architectural style
for distributed hypermedia systems. REST-compliant or RESTful systems, are "stateless" (discussed later in this
Page | 57
article) and separate a client and a server. A web application developed using REST (RESTful web
application) exposes the data or information about its resources which can be anything that the developer wants.
This allows the client using this application to take action on the resources. For example, using information exposed
to users, clients can create a new user.
As another example, suppose we have a pet store and the information related to all pets in the store is stored on the
server. If we want information related to a pet (let's say pet with id=0) then we will access the appropriate URL of
the pet store in the browser (Here the browser will be the client). An example URL can
be "https://demoqa.com/BookStore/v1/Books".
All the methods (coloured buttons) shown in the above screenshot correspond to REST APIs that are executed with
the click of a button. Please note that this is a demo website and therefore the APIs are so explicit on the screen. In
general, all this is done in the back-end and the client is not shown any of this information. Coming back, when we
click the "GET" button (/Books), we will get the response in JSON format that will show us the details of the
particular book. This response is shown below:
Note: When we click on the "GET" button, in the browser we see the link changes
to "https://demoqa.com/BookStore/v1/Books".
We will discuss all the methods shown above (in form of buttons) in our subsequent articles.
Now let us depict the actual REST data transfer in the above example in the diagram below.
Page | 58
As the above diagram shows, the API works as a medium of communication between a database (that is a part of a
server) and a client. When a client sends data through APIs, it goes to the database, do the appropriate
operation (such as add, delete, modify etc.) and return the response data that contains response code, header files,
cookie info etc.
We can summarise the REST characteristics and the working in the above diagram as follows:
• A client access data from the server passed by REST. This can either be through authorized access or without
following any strict guideline.
• As we can see, the application developed using REST is an interactive application and mostly it uses web
services. In this case, the web service follows RESTful guidelines and fulfils the constraints of REST that are
discussed later in this article.
• A web service using REST provides web resources in textual format and allows them to be read and edited
using a predefined set of operations.
REST is a way to access a web service and is often viewed as an alternative to SOAP (Simple Object Access Protocol).
In a RESTFul application, we have entities namely client and resource which are used commonly. Let us discuss them
briefly next.
A client can be a software or a person or a system using the APIs to access data from another application server. For
example, a developer might access Facebook APIs to embed a live post in their own website. The developer program
will call the Facebook API through a browser. So in this case, the browser acts as a client that is calling the Facebook
APIs.
If we visualize this system using the REST diagram above, the client or browser will connect to Facebook-Server over
REST API and then get the information required to render it on the screen.
As another example, suppose I have an application "myHealthApp". I want data on the Covid-19 pandemic from a
city, Pune, for example. To achieve this, I will develop APIs or methods, such as, "Corona API" using which I can
request the data from Pune Municipal Council (PMC). This is done using myHealthApp. This means using
myHealthApp which acts as a client, I will make a request for data using Corona API (say getCoronaData method to
be more specific) through the browser ( for example, https://myHealthApp/getCoronaData). This getCoronaData
method will in turn connect to PMC servers and fetch the required data as a JSON response (or any other
format). On the client side, I can take that data and perform various operations on it. This is the use of APIs.
Any smaller unit that can be transformed and addressed through a URL and HTTP method is considered a resource.
This resource makes changes to the database. For one application, you may have a lot of resources with all of them
assigned a particular task. For example, an online book store may have a resource as a table of the database. A
resource in a REST architecture is anything that a client has access to and can modify or update.
Page | 59
In a way, you can say that a resource is any object for which we need information from API. So in the above example
about Facebook, a resource can be a post, page, or user account. In the example of Corona API, resources are all the
details on Corona like Corona data, pages on treatment, vaccination, etc.
For an API to be RESTful, it has to fulfil or adhere to the following guiding principles or constraints defined by REST.
Uniform interface
The uniform interface principle has the following parts that an API has to follow:
2. The server returns the response and includes information such that the client can modify or edit the resource.
3. The request sent through the API contains the information that the server needs to execute the request. Each
response returned by the server also contains all the information so that client understands the response.
4. Hypermedia as the engine of application state. The application means the web application that is running on
the server. Hypermedia is the hyperlinks or simple links included in the response. So the server basically
informs the client about the ways to change the application web.
Client-server separation
The interaction between the client and the server is independent and is only in the form of requests. The client
initiates a request and the server sends the responses. The response is a reaction to the request. So all server does is
wait to receive requests from the client. It never sends out information about the resources to the client on its own.
For more details on client-server refer to our tutorial, Client-server Architecture.
Stateless
The word "stateless" means the server does not keep track of the user who uses the API. So when a new request
comes in, the server will not know if the same user has sent a GET request in the past for the same resource. It
doesn't remember the resources requested by the user earlier. For example, HTTP is a stateless protocol. HTTP
server does not keep track of any state of information passed to and fro. Hence at any given time, a client can send a
valid command, and the server will not relate or keep track of any previous similar commands.
Hence each request regardless of the other requests made by the user will contain all the data needed by the server
to execute the request and send a response.
Layered system
A layered system provides a hierarchical structure between a client and a server. There can be a lot of intermediaries
between the client and the server working along with REST API without the client's notice. Our clients think there is a
direct connection to the server. We then take advantage of it to improve our architecture and bring down our
distributed system complexity. These intermediate elements provide a security layer, load-balancing layer, and other
functionality to the system. The only guideline is that the presence of these intermediate layers should not affect the
request or response.
Note: The abstraction of layers does not let one layer be aware of the presence of another layer.
Cacheable
The server data received in the response contains information regarding whether the data is cacheable or not. If the
data is cacheable, it will contain some kind of version number that makes caching possible. The client will know
which version of the data it has got from the previous response. This way client can avoid requesting repeated data.
Cacheable data (and therefore version number) also helps the client to know the expiration of version data and the
requirement of a new request to fetch the latest data.
Page | 60
Code-on-demand
This particular constraint "Code on demand" is optional and without fulfilling it we can have a RESTful API.
The client can send a request to the server asking for the code and then the server will respond with some code in
the form of a script or some other entity. For example, servers can extend the client functionality by downloading
and executing pre-compiled code like an applet or a client-side script like JavaScript. So when we click on any video
on Facebook, Facebook will run a precompiled or any third-party software to run that video.
Once an API fulfils the above constraints we discussed, we can say it is a RESTful API.
An API (Application Programming Interface) conforming to the REST architectural style or REST standards is known as
a "REST API". A Rest API facilitates interaction between the client and RESTful web services*( server)* to get the
required information. They can be used for a variety of purposes by interacting with the system. These may include
specific actions such as retrieving the location of a particular city or data updation such as registering a new user. API
developers use REST standards in a variety of ways to develop REST APIs. The following diagram shows a general
REST API functionality.
As shown in the above diagram, REST API sits in the middle layer to the database and the presentation layer i.e. the
interactive systems. The other applications (shown as the top layer) will call the REST API that has centralized core
logic in one place. The applications call REST APIs to access the desired data. For example, if we try to hard code
Page | 61
everything, we need to code for each action on the website. Retrieving book by book serial number is an action that
may need to run through the middle layer and then the database. It can take a lot of time depending on the size of
the database and website. With RESTful APIs, the process becomes much faster as they are lightweight. So instead
of writing separate code and logic for each application, we write REST APIs accessible by any application.
What happens when a client makes a request through the RESTful API?
When a client makes a specific request, RESTful API transfers a state representation of the resource to the requester
or endpoint. The format of this representation is one of several formats like HTTP: JSON (Javascript Object
Notation), HTML, XLT, Python, PHP, or plain text. The most popular format generally used nowadays is JSON since it
is easy to read and is very lightweight.
Headers and parameters also play an important role in the HTTP methods of a RESTful API HTTP request. They
contain important identifier information regarding the request's uniform resource identifier (URI), metadata,
authorization, caching, cookies, etc. These request and response headers have their own HTTP connection and status
code information.
1. As we have discussed earlier, the REST API creates an object and transmits the object values in response to
the client's request. The REST API breaks down this transaction into smaller modules wherein each module
addresses a specific part of the transaction. This breaking down of transactions into smaller modules requires
lots of effort but also provides more flexibility for the user.
2. The REST API has strict criteria to conform to. We have already seen the guiding principles (constraints) for an
application to be RESTAssured in our earlier tutorials of What is REST and Rest Architectural Element. This
strict adherence results in efficient REST APIs after their development. Also, we can implement this set of
guidelines as needed.
3. The REST APIs are considered easier than other protocols like SOAP (Simple Object Access Protocol) that have
more specific requirements like built-in security, transaction compliance, XML messaging, etc. All these
requirements make these protocols slower and heavier.
4. The REST applications (and APIs) are more lightweight, have increased scalability, and are more suited for IoT
(Internet Of Things) and mobile app development.
We perform CRUD Operations when we are working with web technologies and applications. As shown in the below
figure, CRUD stands for Create, Read, Update, Delete. This means using CRUD operations, we can create, read,
update and delete a resource. Generally, we make use of HTTP methods to perform CRUD operations. In the case of
REST API methods, the REST provides these four methods in the form of APIs. Refer to the figure below:
Page | 62
As shown above, POST, GET, PUT and DELETE are the HTTP methods used for CRUD operations. The following table
shows the description of each of these methods as well as an example URL using the swagger
tool https://demoqa.com/swagger/
HTTP
Operation Operation Type Example URL
Method
Replace
curl -X PUT "https://demoqa.com/BookStore/v1/Books/9781449325889"
ISBN object
PUT N/A -H "accept: application/json" -H "Content-Type: application/json" -d "{
with given
"userId": "toolsqa_test", "isbn": "9781449325862"}"
ISBN
Idempotent:
Same results
Delete book curl -X DELETE "https://demoqa.com/BookStore/v1/Book" -H "accept:
irrespective of
DELETE with given application/json" -H "Content-Type: application/json" -d "{ "isbn":
how many times
ISBN "9781449325862", "userId": "toolsqa_test"}"
the operation is
invoked.
So how do we test these methods in a Swagger tool? Let us see an example of GET operation. Navigate to the
following link: https://demoqa.com/swagger/#/BookStore/BookStoreV1BooksGet
We can see the following REST API for GET book details.
Page | 63
Now let us "execute" the GET operation that "gets book details". When we click this button and execute the API,
the below-given command or GET syntax gets executed:
In a similar manner, we can perform other operations as well for which we have crafted dedicated posts. In
subsequent articles, we will learn to create a REST API ourselves.
So here are some of the points we should remember for REST API methods.
• PUT and DELETE methods are idempotent: the response they return is always the same irrespective of the
times the methods are invoked.
• PUT and POST operation are generally the same except for one difference that POST operation can return
different results whereas PUT is idempotent.
Page | 64
In this article, we will focus on these three different classes of the architectural elements identified by REST :
REST uses connectors that manage communication between the different components. There are five types of
connectors that encapsulate the activities of accessing resources. They also enable transferring of resource
representations. All the communication through the connectors is hidden with clean separation thereby enhancing
the simplicity. There are following REST connector types-
1. Client - It initiates communication by sending requests and consumes the response sent by the server.
Examples are HTTP library, client-side web API like libwww.
2. Server - It listens for connections and gives responses to the requests hence allowing access to its services.
Examples are Web server APIs like Apache API, NSAPI, etc.
Page | 65
3. Cache - It is the third connector type which is located at either the client or server connector. It stores
cacheable responses that can be reused for similar interactions. It saves repeated network communication
when employed at the client connector. Alternatively, at the server connector, it saves the repeated response
generation process. Examples are the browser cache or web caching solutions like the Microsoft Azure CDN.
4. Resolver - It translates the resource identifiers into the network address. You know that most of the URIs
consist of DNS hostname. Now the web browser extracts the hostname from the URI and uses the DNS
resolver to fetch the IP address for the naming authority of the resource. Examples are Microsoft DNS, BIND,
etc.
5. Tunnel - It relays information across the connection boundary like the firewall or gateways. REST components
may switch from active to tunnel behaviour. Hence, allowing the client to directly interact with a remote
server using a protocol like TLS. Examples are SOCKS, HTTP Tunnel, etc.
Components in REST architectural elements are the different software that interacts with each other. They act as
end-points connected through connectors and exchanging data elements. There are mainly categorized into four
types as described below-
1. Origin Server - An origin server is designed to consume the incoming requests that modify the value of the
resources of any representation. You may think of it as a container that holds the requested representations
of the resources. It uses a server connector to receive and respond to requests. Web servers like Apache
Tomcat & Microsoft IIS are examples of the origin server.
2. User Agent - A user agent initiates a request at the client end. It uses a client connector to initiate such
requests and becomes the recipient of the response. Web browsers like Mozilla, Chrome, etc are classic
examples of user agents. They act as the starting point of any service requested by the user and render the
response as sent by the servers.
3. Gateway - A gateway is an intermediary imposed by the network. It provides service encapsulation like data
translation(compression), performance enhancement(load balancing), or security enforcement(encryption). It
acts as both the client and the server to facilitate the exchange of requests and responses with possible data
translation. Examples are Squid, NGINX, CGI, etc.
4. Proxy - It is also an intermediary to the requests made by the client for some service or some resources.
Similar to the gateway, it provides an interface for encapsulation of services like load balancing, encryption,
or compression. Examples of proxy are CERN proxy, Netscape proxy, CGI proxy, etc.
The uniform interface between the components of REST architectural style distinguishes it from all other network-
based architectures. It makes all the interactions between the client and the server unified through a fixed set of
operations. Data elements and their state form the key aspect of REST architectural elements. The components
interact by exchanging the representation of the current or desired state of data elements.
Resource
A resource is any addressable information on the server. It is a conceptual mapping to a set of entities and not the
data itself. This mapping can either be static or temporal. A static resource is one that remains unchanged over a
long period of time like a web page address. Alternatively, a temporal resource keeps changing with time, as the
weather information about a city.
Resource Identifier
Page | 66
A resource identifier uniquely identifies a resource also known as URI. The URIs and resources follow a many-to-one
relationship. It means that a resource can have multiple URIs providing differing information about the resource. An
example of resource identifier Bookstore API by ToolsQA. The resource identifier for getting the list of available
books is- https://bookstore.toolsqa.com/BookStore/v1/Books On accessing the above resource identifier you will be
able to see the resources, i.e the list of books present in the database.
Resource Metadata
It describes the different properties of a resource by providing additional information like its location or the alternate
resource identifier. It categorizes the resource and gives information about it.
Representation
Representation is the state of a resource and is data plus the metadata which explains the data. In a real sense, we
do not directly send or receive the resource. Rather, we request and receive the representation of resources. A
representation can either be a document, a file, or even an HTTP message entity. XML and JSON are the most popular
resource representations. In our example of bookstore API, the resource representation is in JSON format.
Representation Metadata
This data element, resource metadata, describes the format type of the response body. This helps in the
interpretation of data at the client end. The representation metadata consists of the different headers used in the
request and response. We have explained all the header types in our previous posts on HTTP request and HTTP
response. But let us still quickly see what all headers are included as representation metadata in our example API.
Page | 67
As can be seen, The resource request defines the content-type as a JSON and also specifies the content-length to set
the limit. The response headers also identify the additional information for the response like the User-Agent,
Connection, Accept-Encoding, etc
Control Data
It defines the purpose of messages exchanged between the client and the server such as the requested action and
response meaning. It also helps parameterize requests and override the connecting elements' default behaviour. For
example, control data can modify the cache behaviour of a request or the response. Additionally, the data
corresponding to a certain condition like the last modification date(If-Modified-Since) or if it matches a certain
parameter(If-Match) can be fetched.
• Latest Versions.
Rest-Assured is an open-source Java-based library useful for testing and validating REST APIs or RESTFul Web
Services. It is like a headless (no GUI) client that accesses and tests the REST Web Services. It was developed and
maintained by Johan Haleby with the support of several other contributors.
Rest assured simplifies the testing of REST-based services. It brings out the simplicity of dynamic languages like
Groovy and Ruby that perform API testing in Java. The library supports any HTTP method and also has explicit
Page | 68
support for GET, POST, PUT, DELETE, OPTIONS and HEAD. It also includes specifications and validation like
parameters, headers, cookies, etc. We can also use it to verify and validate the response of the HTTP requests.
Source
Apart from testing JSON-based web services, Rest Assured can also be used to test XML-based web services. We can
also integrate this library with JUnit and TestNG frameworks and write test cases for applications. Further, it can be
integrated well with Maven and its efficient matching techniques produce straightforward results.
Yet another powerful feature of REST assured is its support for XML Path and JSON Path syntax to check specific
elements of the response data similar to using XPath API. For people new to such concepts, please refer to the
following syntax examples.
XPath syntax:
<bookstore>
<book>
<title>Freedom In Exile</title>
<price>14.29</price>
</book>
</bookstore>
Apart from all the above features, this fantastic library also provides various other features like DSL-like syntax,
Specification Reuse, XPath-Validation, easy file uploads, and all the features that are conducive to automated
testing.
The above discussion about this java library convinces us that it is a reliable library. But why do we need it or what
are the reasons to use it in our application testing?
1. It is an open-source library and has an active development community making it a great choice for API
automation.
2. Earlier, we had to use dynamic languages like Ruby, Groovy for API testing and it was quite challenging.
3. Validation and testing of REST services are harder in Java. Using REST Assured, it becomes simpler and easier.
4. This library uses Java and therefore it becomes simple to send HTTPS requests with customizations using
basic Java code. Once we know the basics of API and integration testing, automation using Rest Assured
gives good confidence on the backend. Thus we can focus more on front-end testing.
Latest Versions
Following are some of the versions of the Rest Assured library we use generally in applications.
1. io.rest-assured - This is a Java DSL for easy testing of REST services. The last release: 11, December 2020
(4.3.3).
2. com.jayway.restassured - This is a legacy library and used for easy testing of REST services using Java DSL.
Last Release: 4 March 2016.
SNo Advantages
It is very rich in syntax and ready-made assertions. Rest Assured requires less coding as compared to Apache
2
HTTP Client.
4 The response is given in JSON or XML format and is easy to parse and validate.
7 The library has a powerful logging mechanism. Also, we can verify headers, cookies, content type, etc on the fly.
It can easily be integrated with other Java libraries like TestNG, JUnit, etc. We can also integrate it with
8
Selenium-Java and achieve end-to-end automation.
Page | 70
SNo Advantages
It supports JsonPath and XmlPath that helps in parsing JSON and XML response. It also has support for the JSON
10
Schema Validation library to verify JSON Schema.
13 Supports Spring Mock MVC, Spring Web Test Client, Scala, and Kotlin.
It follows the BDD (Behavioural Data-Driven) approach and keywords like given() when(), then() which makes
14
code readable and supports clean coding. This feature is available from version 2.0.
1. It does not support the testing of SOAP(Simple Object Access Protocol) APIs explicitly.
2. Using this library requires that the user has good Java programming knowledge
The first step towards setting up the development environment so that we can test some RESTful APIs is to evaluate
the prerequisites. The following list highlights the required software for setting up Eclipse with rest-assured. Before
proceeding, please make sure they are installed on your system.
• TestNG setup.
If any of the above is not present on the system, then we have to follow the links given below :
1. Set up Java
2. Setting up Eclipse
3. Set up TestNg
Page | 71
Once the prerequisites are up and running we can proceed with the rest assured set up on Eclipse.
The rest assured jar files can be downloaded from the following link.
https://github.com/rest-assured/rest-assured/wiki/Downloads.
When we navigate to this page, we can see the section “Current direct downloads”. Go to this section and click on
the link to the dist package.
Note: At the time of this writing Version 4.4.0 is available for download.
Once the link is clicked, the browser will download the rest-assured-4.4.0-dist.zip file on the system (mostly in the
"downloads" folder for Windows OS). Navigate to the folder where the zip file was downloaded and simply unzip the
files.
Now go to the folder where the files were just unzipped and open it. The contents should be the following in this
folder.
Note: We have to also unzip the rest-assured-4.4.0-deps.zip dependency jars. In the end, your folder would look like
this.
Page | 72
Now that we have rest assured jars package ready, we can go ahead and create a project in Eclipse that will use rest
assured.
To add and use unzipped rest assured jars in an actual project, we have to first create a new project in Eclipse. So we
create a project, let's say, RestAssuredTest as shown below.
Page | 73
Once clicked on the Java Project link, a new project window opens up. Enter the name of the project
as RestAussuredTest and click on the Finish button. Once Finish is clicked, we get the following screen. Click Open
Perspective. (Alternatively, if we have already checked the option "remember my decision", then this step will not be
seen)
Page | 74
Now the project with the name RestAssuredTest should display in the package explorer.
Page | 75
Once the project is created in Eclipse, now it is required to add the unzipped jars in the classpath of the Eclipse
project.
Select the Java project folder we just created and right-click on the project folder in the package explorer pane and
choose Properties. This will open up the project properties pop-up window as shown below.
Select Java build path option in the left pane of the properties window. In the Java build path pane, on the left-hand
side, you will see the Libraries pane.
Page | 76
Here we are going to reference the rest assured jar files that we downloaded earlier. To reference the jars, click on
the "Add external jars" button and navigate to the folder where we unzipped all our rest-assured jars. Refer to the
image shown below.
• rest-assured-3.3.0.jar
With this, we have successfully set up a Java project in Eclipse with a rest-assured library. If we now check the
project explorer, we will get the following view.
Page | 77
Now we are ready to use Rest Assured features in Eclipse.
• HTTP Methods and status codes for REST API Automation Testing
Rest stands for Representational State Transfer and is an architectural style for communication with web services.
An API or Application Programming Interface is a set of programming instructions used to access a web-based
software application. The APIs built using REST is called REST APIs which we have discussed in an earlier article. Let
us now begin to understand REST API testing.
Page | 78
So what is REST API testing?
REST API testing is a technique to test RESTful APIs and validate their correctness. We send the request (preferably
using automation) and record the response for further assertions. This way we can check if the REST API is working
fine or not. REST API testing is mainly done using four REST methods, viz, GET, POST, PUT, DELETE.
2. Automation testing: Using scripts or programs that can access REST APIs.
However, in this tutorial, we will only concentrate on automated REST API testing.
HTTP Methods and status codes for REST API Automation Testing
We know that REST API uses five HTTP methods to request a command:
Method Description
PUT Updates the previous resource if it exists or creates new information at a particular URL.
POST Used to send information to the server like uploading data and also to develop a new entity.
Once the request is sent using the above methods, the client receives the numeric codes known as "Status codes" or
sometimes referred to as "Response codes". Then we can interpret these status codes to know what kind of
response the server has sent for a particular request. Status codes are mainly classified into five categories as shown
in the table below.
3 3xx (300 – 399) You are required to take further action to fulfil the request.
4 4xx (400 – 499) There’s a bad syntax and the request cannot be completed.
5 5xx (500 – 599) The server entirely fails to complete the request.
The above codes help us to interpret the outcome of the HTTP requests. From the above table, we can deduce that if
the response status code is 2xx, it means the application is functioning as it should be. The status code 1xx, 2xx, 3xx
are not considered errors but are informative messages and these codes will not affect the user experience.
However, if we get status codes like 4xx and 5xx, these are error messages. This means users will encounter error
messages when they are navigating through the APIs. Errors at the client or browser level mostly result in 4xx status
code error messages. Whereas server-level errors result in 5xx status code error messages. So when performing
REST API testing we should evaluate each response by inspecting the error codes.
Consider the following REST API example URL, https://demoqa.com/swagger/#/BookStore. This is a bookstore
inventory and it provides us with various REST API methods to access information from the bookstore. Now let us
access this URL in the browser and we are presented with the following screen.
Page | 79
Click on the GET method (the first one) in the above store to access the pet inventory. When we click and execute
the GET method, we get the following response.
Note the status code on the above screen (left panel). It is 200 which means the request was successfully executed
and we got a successful response. This way we receive a status code from the server when we send a request and
then we can interpret this status code and check if the request was executed in a normal manner or some error
occurred. We will further explore the response obtained from the server in our upcoming articles.
REST Assured is a Java library for testing RESTful APIs. It is widely used to test JSON and XML-based web applications.
In addition, it fully supports all REST methods like the GET, PUT, POST, PATCH, and DELETE. Next, we will see a
detailed walkthrough of testing one REST API using the Rest Assured library.
To write a sample REST API test we will make use of the following REST API link.
Request
https://demoqa.com/BookStore/v1/Books
URL
HTTP
GET
Method
This URL will return the inventory details of a Book store. There are no input parameters for the
Comments
request.
Page | 80
{"books": [{"isbn": "string","title": "string","subTitle": "string","author":"string","publish_date": "2022-
Response
01-25T13:44:50.276Z","publisher": "string","pages": 0,"description": "string","website": "string"}]}
In fact, if we directly open the above URL in the browser, we get this output as shown below:
To get the same output programmatically using the Rest Assured library, we have to follow below steps:
import io.restassured.RestAssured;
import io.restassured.http.Method;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
@Test
RestAssured.baseURI = "https://demoqa.com/BookStore/v1/Books";
//In this case the request does not take any parameters
// Print the status and message body of the response received from the server
The above code generates the same response as we got in the browser earlier. The following screenshot shows the
response.
In this way, we can make any Test API call and get the response from the webserver hosting RestFul services.
Code line 1
RestAssured.baseURI = "https://demoqa.com/BookStore/v1/Books";
The above line uses RestAssured class to set up a base URI. In this case, the base URI
is “https://demoqa.com/BookStore/v1/Books”. The base URI indicates the root address of the resource we are
going to request from the server (hence the name base URI). Then we will add parameters, if any, when we actually
make the request in subsequent code.
The class io.restassured.RestAssured , is the basis of any kind of HTTP request we make for tests. Some of the key
features of this class are:
• Provides support to create Requests for different HTTP method types (GET, POST, PUT, PATCH, DELETE,
UPDATE, HEAD, and OPTIONS).
• It communicates with the server using HTTP and sends the Request created in the tests to the server.
• Provides support for validating the Response received from the server.
Internally io.restassured.RestAssured class uses an HTTP builder library, which is a Groovy language-based HTTP
client.
Code line 2
Page | 82
// Get the RequestSpecification of the request to be sent to the server.
The next line gets the RequestSpecification of the request to be sent to the server. Rest Assured library provides an
interface called RequestSpecification for this purpose. The variable httpRequest stores the request so that we can
modify it if required like adding authentication details, adding headers, etc. For this particular test, we are not
modifying the variable.
Code line 3
//In this case the request does not take any parameters
Now we call the server to get the resource using the RequestSpecification object. The above code line uses the
request method to send the request for the resource to the server.
The request method takes two arguments, the first is the HTTP method and the second is a string. The string
parameter is used to specify the parameters that are to be sent with the base URI. In this case, to get pet store
details we do not send any parameters hence the blank string. The return type of the request method is
the Response object which means the request method gets the response back from the server.
// Print the message body of the response received from the server
System.out.println("Response=>" + response.prettyPrint());
In the above code lines, we just read the response as a string and print it to the console. We use the getBody method
of response interface that returns the actual body of the response. This is then printed to the console.
We can also write the above test code using short-hand methods provided by Rest Assured. Following is the code
snippet that is shortened a bit.
@Test
RestAssured.baseURI = "https://demoqa.com/BookStore/v1/Books";
// to the server.
Page | 83
// Call RequestSpecification.get() method to get the response.
// as String.
So here we use the "get" method on the RequestSpecification object that returns the Response object.
We will refer to the same example in our next articles when we go into details of
the io.restassured.response.Response interface.
Note: The postman article on the same topic (API test and GET request) can be found at New Request in
Postman and Get Request in Postman.
An HTTP response object typically represents the HTTP packet (response packet) sent back by Web Service Server in
response to a client request. An HTTP Response contains:
1. A status.
2. Collection of Headers.
3. A Body.
So when we say we need to validate HTTP response status, we are looking forward to having a mechanism to read
and validate the entire response object including the status, headers, and the body. Hence, we will validate each of
the HTTP response components separately. So in this article, the validation of an HTTP response status will be dealt
with in three parts as follows:
Page | 84
As we already know the same REST API returns a response message in XML or JSON format. This format depends on
the Media-Type attribute in the HTTP request.
But then how will the client know what type of response it will get from the API? Well, this is managed by the
response headers. Response Header contains a Content-Type attribute that informs about the type of response body
format.
Consider the Swagger UI example we discussed in earlier articles. Suppose we send a GET request to the Book Store
through our browser as follows:
When the above command executes we obtain the response shown in below screen:
As seen from the above screenshot, the response has a status, headers, and a body. If we check the "Response
headers" section, in the above screen, it has a content-type attribute that has the value along with other attributes.
On validating this header, the client knows what type of response (body) we can expect.
Let us now proceed with validating the status part of the response.
When the client requests a piece of particular information from the server, the server sends a response with a status
code back to the client. The status code that the server returns tells us whether the request was successful or not. If
the request was successful, the server sends the status code in the range of 200-299. If the request was not
successful, then the status code other than the range is returned. We can get the list of HTTP status codes along with
their description on the W3 page.
Rest Assured library provides a package named "io.restassured.response" which has a Response interface. The
Response interface provides methods that can help to get parts of the received response. The following screenshot
shows some of the important methods of the response interface.
Page | 85
The method getStatusCode() is used to get the status code of the response. This method returns an integer and then
we can verify its value. TestNG Assert is used to verify the Status Code. Now consider the code given below:
import org.testng.annotations.Test;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
@Test
RestAssured.baseURI = "https://demoqa.com/BookStore/v1/Books";
Page | 86
int statusCode = response.getStatusCode();
The below line of code extracts the status code from the message:
The return value "statusCode" is compared with the expected value i.e. 200. If both values are equal, then an
appropriate message is returned.
Assert.assertEquals(statusCode /*actual value*/, 200 /*expected value*/, "Correct status code returned");
If you run the above test, you will see that the test passes since the web service returns the status code as 200 as
shown in the below image.
In this manner, we can verify the status code of the response using the "getStatusCode()" method of the response
interface. Please note that since we already knew that the success code here is 200, we wrote the appropriate code.
Your server may respond as success with a code anywhere between 200 and 299. It is best to check that out
beforehand. Let us now move on to discuss how to validate the status code that returns values other than 200 i.e.
error status code.
So far the request-response situations are all good and we have only received 200 status codes indicating successful
requests. But this may not be always true in the real world. There can be reasons like the server is down or REST API
not functioning properly or the requests themselves may be problematic. In conclusion, we may face the following
scenarios:
4. An error occurs on the server side during the processing of the request.
So when any of the above scenarios occur, the REST API will return an appropriate status code other than 200. The
client in turn has to validate this status code and process it accordingly.
Page | 87
For the ToolsQA Book Store service, let’s create another test with an erroneous scenario. Here we will validate the
HTTP status code returned by Book store Web Service when an invalid parameter is entered.
So here we provide the parameter to get user details. Here we provide nonexistent userId as the parameter. The
code looks as below:
import org.testng.annotations.Test;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
@Test
RestAssured.baseURI = "https://demoqa.com/Account/v1/User/";
When we run this test it returns the error code of 401. We can see the result of the test execution below.
Page | 88
Note: We can make a quick change to the code above to make sure the test passes. This change is shown below:
Assert.assertEquals(statusCode /*actual value*/, 401 /*expected value*/, "Correct status code returned");
So here we expect the value returned to be 401 instead of 200, hence the test is passed. Next, we will validate
the "Status line".
A "Status-Line" is the first line returned in the HTTP response. The status line consists of three substrings:
• Status Code.
For example, when the request is successful the status line will have the value "HTTP/1.1 200 OK". Here, the first
part is the HTTP protocol (HTTP/1.1). Next is the HTTP status code (200). The third is the status message (OK).
We can read the entire status line using the method getStatusLine () of the response interface. The following code
shows the demonstration.
@Test
RestAssured.baseURI = "https://demoqa.com/BookStore/v1/Books";
// Get the status line from the Response in a variable called statusLine
Here we perform a similar test as we have done for the status code. We read the status line using the
getStatusLine () method into a string value. Then we compare this returned value with "HTTP/1.1 200 OK" to check if
the status is successful.
Note: The postman article on the same topic (Response in Postman) can be found at Response in Postman.
Page | 89
Validate Response Header using Rest Assured
REST assured has been of great use to us for testing APIs and validating a lot of things. For instance, in the last
tutorials, we performed a sample Test call using Rest Assured and also validated response status. But that is just one
part of the overall response testing when it comes to automation. There is a lot more that we need to validate in
order to be an efficient tester and test the quality of our APIs. In this article, let us validate the Response Header
using Rest Assured with the following topics in focus:
• How to access and read HTTP Response headers using REST Assured?
The response received from the server consists of zero or more headers along with response status and response
body. Each header is a key-value pair. The header part of the response is used by the server to send extra
information which is also referred to as "Metadata" of the response.
For example, headers contain a "Content-Type" attribute that tells us how to interpret the data of the response
body. So if the response body contains JSON data, then the corresponding content-type attribute in the header will
be "application/json". Similarly, if the data in the body is XML the Content-Type header will be "application/xml".
Note the response header that is obtained (red rectangle). Since the body is JSON, the Content-Type is set to
"application/JSON".
The Response interface of the Rest Assured library provides methods to access all headers or individual headers. Just
typing "Response.head" in Eclipse (or any such editor) will show all the methods supported to access headers.
As shown in the above screenshot, the Response interface of REST Assured provides methods related to headers.
When all the headers in a Response are returned, we can print each header by simply iterating over each of them.
Page | 90
Note: The collection of headers is represented by a class called io.restassured. HTTP.Headers. This class implements
the Iterable interface. Hence, we can use the "for each (for( : ))" loop to read all the headers.
How to access and read HTTP Response headers using REST Assured?
Now let us see how we can read a Header using Rest-Assured. Let’s write a test to record the following Header Types
from the Response:
• Content-Type.
• Server.
• Content-Encoding.
@Test
{ RestAssured.baseURI = "https://demoqa.com/BookStore/v1/Books";
// Get all the headers and then iterate over allHeaders to print each header
In the above code, we access all headers and then extract individual headers by looping through the Headers
collection. Shown below is the console output of the above test.
The above output shows all the header key-value pairs that we displayed using for loop in the code.
Let us demonstrate the .header(String arg0) method to get a particular header. Here we pass the exact header
name as an argument.
@Test
RestAssured.baseURI = "https://demoqa.com/BookStore/v1/Books";
In the above code, we are accessing Content-Type, Server, and Content-Encoding headers by specifying respective
headers names as an argument to the header() method. Shown below is the console output of the above code.
Note: Response.GetHeader(String headerName) method behaves exactly the same way as the
Response.Header(String headerName) method. So the above code can be written by replacing the ".Header()"
method with the ".GetHeader()" method.
Now that we have had a discussion about methods that access header, let us write a test to validate the values of
the header by putting it as Assert. The below code shows the test that is similar to the code in previous sections but
only uses Assert to validate the results.
@Test
RestAssured.baseURI = "https://demoqa.com/BookStore/v1/Books";
In the above code, we verify the actual value of each header viz., Content-Type, Server, and Content-Encoding with
the expected value. Shown below is the screenshot of the test result.
This output indicates that the actual value and expected value of each header matches.
Now suppose we provide the expected value of Content-Type to "application/XML" in the above code as below.
If we run the same test above after the change, we will get the following output.
As we can see, the difference in actual value "application/JSON" and the expected value "application/XML" raises
an assertion error.
In this way by using the header-specific methods of Response interface, we can validate the Response Header in Rest
API.
In this tutorial, we will learn about How to Read JSON Response Body using Rest Assured? and How to Validate
Content of a Response Body?
Let us continue with the example of Weather web service that we used in the previous tutorials. When we request
for the Weather details of a particular city, Server responds by sending the Weather details of the city as the
Response Body. Response interface contains two methods to get the Response Body
Page | 93
Using these methods we can get an Object of type io.restassured.response.ResponseBody. This class represents the
Body of a received Response. Using this class you can get and validate complete or parts of the Response Body. In
the below code we will simply read the complete Response Body by using Response.getBody() and will print it out
on the console window.
@Test
RestAssured.baseURI = "https://restapi.demoqa.com/utilities/weather/city";
ResponseBody interface also has a method called .asString(), as used in the above code, which converts
a ResponseBody into its String representation. If you run this test the output will look something like this:
Page | 94
Note: Response.body() method does exactly the same thing. So you can even use .body() method in the above code.
ResponseBody can return the response body in a String format. We can use simple String methods to verify certain
basic level of values in the Response. For e.g. we can use the String.contains() method to see if the Response
contains a "Hyderabad" in it. The below code shows how to check for sub string presence.
@Test
RestAssured.baseURI = "https://restapi.demoqa.com/utilities/weather/city";
// To check for sub string presence get the Response body as a String.
// Do a String.contains
We can also ignore the casing using the String internal methods. To do this we will convert the Response in lower
case and then compare it with our lower case string value. Below code demonstrates that.
@Test
RestAssured.baseURI = "https://restapi.demoqa.com/utilities/weather/city";
// To check for sub string presence get the Response body as a String.
Page | 95
// Do a String.contains
// convert the body into lower case and then do a comparison to ignore casing.
The above two approaches suffer from a classical problem, what if the string "Hyderabad" is present in a wrong
node or may be multiple instances of the same string are present. This is not a fool proof way of testing a particular
node in the Response. There are better ways, Response interface gives you a mechanism to extract nodes based on a
given JsonPath. There is a method called Response.JsonPath(), which returns
a io.restassured.path.json.JsonPath Object. This object can be used to further query specific parts of the Response
Json.
• What is JsonPath
• JsonPath expressions
Let us continue with the above example and retrieve the City from the Response. To do so, we will simply get
the JsonPath object from the Response interface and then query for the particular node. Just to be very clear, let us
look at the Weather API response again.
"City": "Hyderabad",
In this response, if we want to go to the City node, all we have to do is have the following JsonPath: $.City. Try it out
on the JsonPath Evaluator to verify the output.
Now let us look at the code, pay specific attention to the comments in the code.
Note: In Java JsonPath you do not need to have $ as the root node. You can completely skip that.
@Test
RestAssured.baseURI = "https://restapi.demoqa.com/utilities/weather/city";
Page | 96
RequestSpecification httpRequest = RestAssured.given();
// First get the JsonPath object instance from the Response interface
// Then simply query the JsonPath object to get a String value of the node
// specified by JsonPath: City (Note: You should not put $. in the Java code)
The output of the code passes the assertion and it also prints the City name retrieved from the Response. As shown
in the image below
On the similar lines, you can extract any part of the Json response using the JsonPath implementation of Rest-
Assured. This is very convenient, compact and easy way to write tests.
Sample Code to read all the nodes from Weather API Response
Now that we know how to read a node using JsonPath, here is a small piece of code that reads all the nodes and
prints them to the Console.
@Test
RestAssured.baseURI = "https://restapi.demoqa.com/utilities/weather/city";
// First get the JsonPath object instance from the Response interface
Similar to the examples used in the previous articles we will be using the Bookstore API in this article as well.
Consider the below sample URL to fetch details corresponding to a book-
Page | 98
https://demoqa.com/BookStore/v1/Book?ISBN=9781449325862 Though the above URL looks very basic, it still let
us understand its different components.
• https:// - It is a protocol that ensures secure connection between the web server and the web browser.
• https://demoqa.com/swagger/#/BookStore - It is the domain name that hosts the website. It generally ends
with .com, .in, .net, etc.
• BookStore/v1/Book - This is the path or the URI that identifies the resource applied by the request.
• ?ISBN=9781449325862 - This is a string query parameter. The question mark denotes the start of a query
string parameter. There can be one or more query parameters in the URL.
Let us now understand more about query parameters in the next section.
You might not always want to fetch all the results corresponding to a request. There may be scenarios where you
need to fetch only a few or a single record. In such cases, query string parameters play an important role. These are
appended at the end of the URL after using a '?'. Try entering the example URL in the browser address bar and
observe the results available under Network -> Payload-
The query parameter, i.e., ISBN=9781449325862, is displayed under the Query String Parameters field. In a similar
way, if there are multiple query parameters passed in the URL, you will see all of them in this field. As an exercise,
you may search some keywords on Google search and see the query parameters that get appended to the URL.
Observe the search keyword is displayed after 'q=your search keyword'. Additionally, you will observe other query
parameters which are separated from each other through an '&' sign.
These signs are termed URL parameters and are beyond the scope of our discussion here.
Now that we have understood what query parameters are and how they are used in requests, we can proceed to see
how we can send requests with Query Parameters in Rest Assured.
In this section, we will see how we can automate our test case by passing query parameters in Rest assured. We will
simply use the URL containing the query parameter as discussed in sections above to show how we can send a
request using query parameters in rest assured. Let us see how the code would look like and then we will
walkthrough it step by step.
package bookstore;
import org.junit.Test;
import io.restassured.RestAssured;
import io.restassured.path.json.JsonPath;
import io.restassured.response.Response;
import io.restassured.response.ResponseBody;
import io.restassured.specification.RequestSpecification;
Page | 99
public class QueryParam {
@Test
RestAssured.baseURI= "https://bookstore.toolsqa.com/BookStore/v1";
//Creating object of JsonPath and passing the string response body as parameter
RestAssured.baseURI= "https://bookstore.toolsqa.com/BookStore/v1";
We first define the base URI to create a request to the service endpoint.
Next we send the resource details like the book ISBN as a query parameter to search in books using the GET request.
Note: If you need to send multiple query parameters you simply need to append queryParam() method with the
parameter name and value to the RequestSpecification object, i.e. httpRequest in the above case.
Page | 100
System.out.println("The book title is - "+title);
Finally, we are storing the response body as a String object and parsing its different values using the JSONPath object.
We then fetch the title from the response body.
Note: You may read more about JSONPath in our elaborate article on the same.
And that's it! See how easily we could send the query parameters to our request by simply using
a queryParam() method. The above code execution displays the title of the book with respect to the ISBN.
You can now go ahead with automating your test scripts with request having query parameter(s) and enhance your
rest assured code.
We use the verb "Post" everywhere when we are dealing with the web. For example, when we are submitting any
registration form on a particular webpage like Gmail. We provide the required data and click submit. So through this
action of submitting data, we are actually POSTING or sending the data to the server. The verb "POST" in HTTP, also
called as POST request method in HTTP sends data to the server. In our example, we are sending our names, email
and decided password as data.
Now let's go to Swagger UI of API https://demoqa.com/BookStore/v1/Books Next, let's create a new user using
POST request as shown in the following screenshot.
In the above example, we have provided all the details for the new user including id and ISBN. When we "execute"
requests we initiate a POST request and send all the information to the server. On the server side, the new user will
Page | 101
be created with all the provided information and a response will be sent back to the client. Look at the following
screenshot.
Have a look at the "curl" command that has a POST request with all the data. The operation is successful and hence
we get the response code as 201.
The content-type parameter is "application/JSON" in the above example. The data sent to the server by POST
request can also be XML(content-type: application/XML). This data is in the body of the HTTP request. As we learned
from the above example, the POST method usually creates a new record in the application database. Although, it is
not always true. Sometimes in creating web applications we use POST request redirections to ensure that no one hits
that URL directly without proper navigation channels. For example, you must have noticed that refreshing or
pressing "back" on payment pages does not work directly. It is secure as the data being sent is not visible in the URL
string. The data can also be encrypted using HTTPS (HTTP Secure) to enhance security.
As far as real-world applications are concerned, the POST request can have a very big size and also a complex body
structure. Since it provides an extra layer of security, we often use it for passing sensitive business-related data. It is
also noteworthy here that the POST request does not always require all the data to be filled by the user. It
completely depends on the server implementation and therefore you should always go through the documentation
before.
In Rest Assured, we make use of the post() method to make an HTTP POST request.
For making an HTTP Post request using Rest Assured, let's add a simple JSON library in our classpath so that we can
create JSON objects in the code. We can use the following URL to download simple JSON from the
Maven: https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple. Once the jar is downloaded
we can add it to the classpath.
Following are the steps we'll follow to make a POST Request using Rest Assured.
RestAssured.baseURI = "https://demoqa.com/BookStore/v1/Books";
In the above code, we initialize a base URI with a link to the bookstore and the 'createUser' API. Next, we create a
'request' using RequestSpecification.
Note: Above code is self-explanatory. In case of any problems, please refer to previous tutorials.
Next, we will create a JSON request object that will contain the data we need to create a new user. Given below is
the code for the same:
requestParams.put("userId", "TQ123");
requestParams.put("isbn", "9781449325862");
In the above code, we have created a JSONObject variable (JSONObject belongs to org.json.simple package). Here
we provide a JSON String containing the data to post to the server. Here we have the requestParams object above
for our test web service with multiple nodes in the JSON. Each node is added to the JSON string using
the JSONObject.put(String, String) method. Once all the nodes are added in this manner, we get the String
representation of JSONObject by calling JSONObject.toJSONString() method.
Now that we have created the JSON string with the required data, the next step will be to add this JSON to the
request body and send or post the request. Look at the following code:
So in this step, we simply add the JSON String to the body of the HTTP Request and set the Content-Type header
field value to application/JSON. Next, we use the method RequestSpecification.body(JsonString) to put the JSON
body into the request. Using this method we can update the content of the HTTP Request Body.
Next using the post () method on the request object we send this data to the server using the
'BookStoreV1BooksPost' API.
Note: Calling the RequestSpecification.body method multiple times updates the body each time to the latest JSON
String.
After posting the request we have to validate the response we received from the server as a result of a POST
request. Given below is the code for validating the response:
Here we read the status obtained using the statusLine() method and print it to the console.
So what happens when we change the HTTP Request method on a POST request? For example what happens when
instead of the expected POST we send the GET? Let's discuss this scenario.
Following is the code wherein we have sent a GET request to an Endpoint when it actually expects POST.
RestAssured.baseURI ="https://demoqa.com/Account/v1";
requestParams.put("userName", "test_rest");
requestParams.put("password", "Testrest@123");
request.body(requestParams.toJSONString());
System.out.println(response.getStatusLine());
System.out.println(body.asString());
We can clearly see the output says the incorrect usage of the HTTP Request Method. Similarly, we have other
negative scenarios listed below which we will leave to users to try themselves.
You can try the above scenarios on the same URL used above to demonstrate the POST request.
Page | 104
Serialization and Deserialization in Java
Serialization and Deserialization in Java is an important programming concept. It is applicable to all major
programming languages. In this chapter, we will try to understand this concept in the context of Java language. At
the end of this chapter, we will be able to
Let us first define the two terms in Generic form, irrespective of any programming language.
What is Serialization?
Serialization is a process where you convert an Instance of a Class (Object of a class) into a Byte Stream. This Byte
Stream can then be stored as a file on the disk or can also be sent to another computer via the network. Serialization
can also be used to save the sate of Object when the program shuts down or hibernates. Once the state is saved on
disk using Serialization, we can restore the state by DeSerializing the class from disk.
Let us try to visualize this using a small diagram. In this diagram, we will create a small class called Rectangle, which
represents a real-life rectangle. Here is the code for the class
this.height = height;
this.width = width;
Note: This class is not yet Serializable as per Java standards, let us ignore it for the time being.
Page | 105
Serialization process on the Rectangle class will look like this.
The encoding scheme that is used to convert from an Object of Class Rectangle to Byte stream is governed by the
Serialization encoding standards mentioned here.
Serializable Interface
In Java, a Serializable object is an object which inherits from either of the two interfaces
• java.io.Serializable
• java.io.Externalizable
Serializable interface is a marker interface. Which means that you do not have to implement any methods if your
class derives from this interface. This is just a marker and the Java runtime, when trying to Serialize the class, will just
check for the presence of this interface in the class. If Serializable interface is present in the class inheritance
hierarchy, Java run time will take care of Serialization of the class.
On the other hand, the Externalizable interface is not a marker interface. If you derive from Externalizable interface
you have to implement these two methods
• readExternal(ObjectInput input)
• writeExternal(ObjectOutput output)
We should inherit from Externalizable interface only when we want to overtake the Java's default serialization
mechanism. If you want to use the default Java's serialization mechanism than you should inherit from Serializable
interface only.
With this understanding, our Rectangle class will now inherit from Serializable interface.
Page | 106
private double height;
this.height = height;
this.width = width;
Let us quickly take a look at the Serialization process in Java. In this process, we will perform these four steps
1. We will create a new FileOutputStream of a file where we want to serialize the class
4. Finally, we will close all the stream objects to save properly write and terminate all streams.
Below is the code to perform the task. Pay attention to the comments that are mentioned above every line of code.
try {
// This file object will be used to write the serialized bytes of an object
Page | 107
// Step 2: Create a ObjectOutputStream, this class takes a files stream.
// This class is responsible for converting the Object of any type into
// a byte stream
objectStream.writeObject(classObject);
objectStream.close();
fileStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
SerializeToFile(rect, "rectSerialized");
When we run this program, it creates a file named "rectSerialized" in the root folder of the project. Just browse to
that location and try to open the file using a notepad. Below image shows that
Page | 108
When you open this file you can see that it contains garbled characters. The contents are encoded and are not in
human readable format. As shown in the image below.
This shows what exactly serialization means and how we can serialize an object in Java. This should also give you a
practical understanding of the different steps involved in serialization process including the input and output results
of the different steps.
In the previous section, we learnt the Serialization converts a class instance into a byte stream which is then stored
in a file on disk. Let us quickly take a look at the Deserialization process in Java, which is opposite of Serialization. In
this process, we will read the Serialized byte stream from the file and convert it back into the Class instance
representation. Here are the steps that we will follow.
1. We will create a new FileInputStream to read the file which contains the serialized byte stream of the target
class. Rectangle class in our case.
3. We will then read the object using ObjectInputStream and store it in a variable of type Rectangle.
4. Finally, we will close all the stream objects to save properly write and terminate all streams.
Below is the code to perform the task. Pay attention to the comments that are mentioned above every line of code.
try {
Page | 109
// Step 2: Create an object stream from the file stream. So that the content
// Step 3: Read the content of the stream and convert it into object
objectStream.close();
fileStream.close();
return deserializeObject;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
SerializeToFile(rect, "rectSerialized");
Just to verify that the original state of the Rectangle class is restored, we will debug the code and
inspect deSerializedRect variable. The below image shows that the original state of (Height: 18 and Width: 78)
Rectangle class is restored.
I hope that this tutorial clears the basic concept of Serialization and Deserialization in Java for you.
Serialization and Deserialization are programming techniques where we convert Objects to Byte Streams and
from Byte Streams back to Objects respectively. We have already discussed this technique in the article Serialization
and Deserialization in Java. We will now cover the following topics in this article:
Serialization, as mentioned above, is a process of converting data objects into a stream of data. The reverse process
of serialization (stream to object) is deserialization. Both the processes are platform-independent. This means we
can serialize an object on a Windows platform and deserialize it on macOS.
As far as rest assured is concerned, we are aware that the data exchange between client and server takes place in
JSON format by REST web service. The stream of data here is JSON data.
when the above object is serialized into JSON, the output will look like the one shown below:
Page | 111
"tools":[1, 3, 7, 9],
"api":"QA"
The above data string can be stored or transferred anywhere. The recipient will then deserialize the data back to its
original format ie object.
Java POJO classes are one way we can serialize the objects and use them in Rest Assured. The details of
implementation are beyond the scope of this tutorial. Serialization is discussed in our previous tutorial Serialization
and Deserialization in Java. While working in the testing industry, we will be more concerned about deserialization.
The same is discussed in the next section in detail.
Before going ahead, it is recommended to read the article REST Api testing in Rest-Assured and converse yourself
with REST, API testing, REST Assured and other similar concepts.
In REST APIs, the process of deserialization is performed especially for the JSON responses we receive from the API.
So, when we say we are deserializing the JSON, this means we convert the JSON format into a type we prefer, most
frequently POJO (Plain Old Java Object) classes.
So in this process, we essentially tell our code to use strongly typed strings that are less error-prone instead of JSON
strings. Let's go ahead and see practically how to deserialize the JSON responses to class with Rest Assured.
We will continue from our example in Making a POST request using Rest-Assured to implement deserialization of
JSON responses. In this article, we have seen that a successful post request sends the following response:
"SuccessCode": "OPERATION_SUCCESS",
In the POST request example, we have used JSONPath to validate the response body parts. Now we have to convert
this response body to a Java class (POJO). In other words, we'll convert the JSON which is a string form to a class
form i.e. deserialize JSON.
Note: Deserialization is also called Object Representation of structured data. The structured data here is JSON.
First and foremost we need to create a class that has all the nodes (or key) of the JSON response. As we are already
aware, the Success response has two nodes:
• SuccessCode
• Message
Both these nodes contain String values. The screenshot below shows the part of the response we receive.
Page | 112
So we have to create a class with two string variables that will represent nodes in the JSON. Given below is the class
code for the same.
@Test
Now that we have a JSONSuccessResponse class to store all the nodes present in Successful Response, let's
understand how to use Rest-Assured to automatically convert JSON Response Body to the instance of the
JSONSuccessResponse class.
The class io.restassured.response.ResponseBody that represents the response in Rest Assured, has a method
called .as(Class<T>). Here, Class<T> is a generic form of any class of type T which is also referred to as template class.
In this case, Class <T> will be JSONSuccessResponse.
• Copy the JSON node variables to the respective instance variables of the class. For example, the value of
SuccessCode node to the variable SucessCode and value of Message to variable Message.
@Test
RestAssured.baseURI ="https://demoqa.com";
requestParams.put("UserName", "test_rest");
requestParams.put("Password", "rest@123");
request.body(requestParams.toJSONString());
Assert.assertEquals("OPERATION_SUCCESS", responseBody.SuccessCode);
Once we get the value in responseBody variable, we can validate the response as shown in the code below.
// Response.
Assert.assertEquals("OPERATION_SUCCESS", responseBody.SuccessCode);
In this way, we can apply assertions to validate the response or even pass this response as input to other tests.
In the previous section, we discussed how to deserialize the JSON in case of a successful response. But in real-time
applications, we can also receive responses that are failures. In such a case, Rest API may return a completely
different response body. One such format of failed response may be as shown below:
"fault": "FAULT_USER_ALREADY_EXISTS"
If we use the class JSONSuccessResponse to deserialize the above response, it will not work. This is because Rest
Assured will not find the nodes SuccessCode and Message in the response body like in the above section. These two
variables in the class will have values as null.
The solution to this is to maintain another class that will be used for deserializing the failure response. This class will
have the following structure.
String FaultId;
String fault;
But now that we have two classes, one for a successful response and another for failure, how can we handle both
these in an application?
We can do this using the HTTP Status Code returned by the server. Rest API in this series returns Status Code =
201 in case of success and 200 in case of failure.
So by making use of the status code we can deserialize the response into appropriate POJO classes depending on
success or failure. Below given code is an updated version of the above code and it takes care of success as well as
failure response.
@Test
RestAssured.baseURI ="https://demoqa.com";
requestParams.put("UserName", "test_rest");
requestParams.put("Password", "rest@123");
request.body(requestParams.toJSONString());
System.out.println(response.body().asString());
if(response.statusCode() == 200) {
Assert.assertEquals("FAULT_USER_ALREADY_EXISTS", responseBody.fault);
Assert.assertEquals("OPERATION_SUCCESS", responseBody.SuccessCode);
In the above code, we deserialize the response to JSONSuccessResponse or JSONFailureResponse class depending on
whether the Status code is Success or Failure.
Note: Another way to deserialize multiple responses is by using the inheritance chain which readers can implement as
an exercise.
• Authentication tokens
Page | 115
• Secret keys
In the context of REST API, we will be more interested in the first three options. The Authentication and
Authorization models that we will discuss are spread across multiple tutorials, starting from this tutorial.
Authentication is a process to prove that you are the person you intend to be.
For e.g. while logging into your email account, you prove that you are you by providing a Username and a Password.
If you have the Username and the Password you are who you profess to be. This is what Authentication means.
In the context of REST API authentication happens using the HTTP Request.
Note: Not just REST API, authentication on any application working via HTTP Protocol happens using the HTTP
Request.
Taking the example of email login, we know that in order to Authenticate our self we have to provide a username
and a password. In a very basic Authentication flow using Username and Password, we will do the same thing in
REST API call as well. but how do we send the Username and Password in the REST request?
A REST request can have a special header called Authorization Header, this header can contain the credentials
(username and password) in some form. Once a request with Authorization Header is received, the server can
validate the credentials and can let you access the private resources.
Note: I hope from previous tutorials you are able to understand the meaning of a Resource. If not, please go
through this tutorial: Rest architectural elements. A private resource is one that is not accessible to everyone. You
need to Authenticate yourself to access the private resource. For e.g. the email inbox, you have to log in to see the
emails.
Let us see it with an example, we have created an API that needs a valid Username and Password to access the
Resource.
Endpoint: http://restapi.demoqa.com/authentication/CheckForAuthentication
In the code below we will try to hit the URL and see what is the Response that we get.
@Test
RestAssured.baseURI = "https://restapi.demoqa.com/authentication/CheckForAuthentication";
Page | 116
In the code above we are simply making an HTTP GET request to the endpoint. In this code, we have not added
any Authorization header. So the expected behavior is that we will get Authorization error. If you run this test, you
will get the following output.
Status message:
"StatusID": "FAULT_USER_INVALID_USER_PASSWORD",
The output clearly says that we have "Invalid or expired Authentication key provided" error. This means that either
there was no Authentication information or the information supplied was invalid. Eventually, the server denies our
request and returns an error response.
Note: Pay special attention to the Status code returned. In case of , Authentication failures Server should respond
with a status code of 401 Unauthorized.
Try to hit that URL using a browser. You should get a Username and Password prompt. The below image shows what
you should be getting when you hit this URL from the browser.
In this tutorial, we will not discuss how to pass Authentication information in the Request header. Here we will only
focus on the definitions of Authentication and Authorization. In the next set of tutorials, we will see
different Authentication models, which will solve the above problem.
Page | 117
What is Authorization? and How does Authorization work in REST WebServices?
Authorization is the process of giving access to someone. If you are Authorized then you have access to that
resource. Now to Authorize you to need to present credentials and as we discussed earlier that process is called
Authentication. Hence Authorization and Authentication are closely related terms and often used interchangeably.
Before ending the tutorial let us see the contents of the private resource in the URL mentioned above. To do that
enter the following credentials
• Username: ToolsQA
• Password: TestPassword
The server will be able to Authenticate and then Authorize you to access the private resource content. The below
image shows the content after successful Authentication.
With this basic understanding of Authentication and Authorization, read the coming tutorials where we will discuss
the specif types of Authentication models in REST API.
Basic Authentication
In our series, we have so far covered the basics of Rest Assured, the different types of requests
like POST, PUT and DELETE. In addition, we also covered the basics of Authentication & Authorization concepts of
Rest API. Practically in the projects, as we proceed with automation, we come across complex APIs. These require
basic authentication implementation mixed along with other code. In this article, we will cover the handling of basic
authentication in Rest Assured. We will focus on the below points-
▪ Preemptive Authentication.
o Digest Authentication.
o Form Authentication.
o OAuth Authentication.
▪ OAuth1
▪ OAuth2
While going through the previous tutorials you must have noticed that we have used the username and the
password (authentication credentials) for certain APIs. This credential setting is to enforce access control for the web
resources and is generally passed in the header field of an HTTP request. The implementation of basic authentication
Page | 118
is to ensure that the APIs are secured and only the users who are authorized have the access to view them. Hence,
the authentication information is not encrypted or hashed but encoded as base-64. We will now see the different
schemes used in Rest Assured for authentication and you may go through our previous article on Authentication and
Authorization for more information.
To test and validate any secured API, you will have to use some authentication scheme. Rest Assured provides
several authentication schemes which we are going to discuss in this part.
Before proceeding to understand the use of authentication in Rest Assured, let us execute our Rest Assured test
without using any sort of authentication. Below is the code for your reference-
package org.example;
import org.testng.annotations.Test;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import io.restassured.response.ResponseBody;
import io.restassured.specification.RequestSpecification;
@Test
The code is pretty simple and uses the get () method to send requests to the server. Do not worry if you don't
understand. It will be explained in the later examples. On executing this code the result would be-
Page | 119
Observe the message in the first line - "Data from the GET API - Unauthorized". This is the issue that we are going to
fix using the basic authentication in our rest assured tests. Let us quickly jump on to understanding the same.
As discussed above, the basic authentication scheme uses the username and password in base64 encoded format.
The request header needs to contain the credentials of the user for access to the resource. It is very easy to send the
credentials using the basic auth and you may use the below syntax-
In the given method you need to append the method of authentication specification followed by the basic HTTP auth
where you will pass the credentials as the parameters. Another type of basic authentication is preemptive which we
will discuss next.
package org.example;
import org.testng.annotations.Test;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import io.restassured.response.ResponseBody;
import io.restassured.specification.RequestSpecification;
@Test
Preemptive Authentication
By default, Rest Assured uses the challenge-response mechanism. This means that it waits for the server to
challenge rather than send the credentials directly. By using the preemptive directives we can avoid that additional
call that the server makes and hence additional complications. In a way, it is similar to the basic auth we saw above,
the only difference is that an additional premptive () directive adds after auth (). Let us see its syntax followed by a
working code example.
package org.example;
import org.testng.annotations.Test;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import io.restassured.response.ResponseBody;
import io.restassured.specification.RequestSpecification;
@Test
//Using the preemptive directive of basic auth to send credentials to the server
The code example used above is a simple Get API where we are trying to fetch the details corresponding to the user.
Note that the server needs the authentication details of the user to get a successful response. Let us glide through
the code line-by-line.
An object of RequestSpecification is created and using the preemptive directive the credentials of the user are sent
in the header. Note that irrespective of being asked for the credentials these would be passed to the server.
The endpoint URL is accessed using the get method and the response is saved using the ResponseBody object.
Finally, we convert the response body to string and print the result. Similarly, you may add additional validations as
per your requirements.
Page | 121
Console prints the response of the above code without errors.
And there you go! You have successfully retrieved the user data by simply adding the preemptive authentication in
your code and passing the credentials.
Digest Authentication
It is somewhat similar to challenge-based authentication but is more secure as it uses a digestive key in subsequent
requests. If at all it is intercepted by an eavesdropper, he will get access only to the transaction performed and not
the user password. The transaction might be replayed but a new transaction cannot be made as the password is not
exposed. Its syntax is similar to basic authentication-
Note that we cannot use the preemptive () similar to basic auth since this scheme uses only challenged
authentication.
Form Authentication
There can be many cases when you need to pass the authentication credentials in an HTML form. This request is
generally sent as a post method where the credentials entered in the form are used for authentication. So, if your
application uses such a form-based authentication you can easily automate it using the form() scheme. The syntax
for it follows-
given ().auth ().digest ("your username", "your password").get ("your endpoint URL")
If you use this approach then Rest Assured will first have to parse through the HTML response to find the fields for
input and then send the form parameters. However, there is a high possibility that this approach might fail if the
webpage is complex. Additionally, it would also fail if the context path is not included in the action attribute of the
service. To optimize it to handle such cases, you may use the below format where you explicitly pass the required
fields by providing the FormAuthConfig()-
OAuth Authentication
Another type of authentication is OAuth authentication. OAuth is an authorization framework that defines an
identity protocol. It has wide usage in web applications and there are high chances that you will have to automate
those authentication actions. These can be of two types viz, OAuth 1.0 and OAuth 2.0 which we will discuss now.
OAuth 1.0
Secured resources built using OAuth 1.0 requires passing consumer key, secret, access token, and token secret. The
syntax it follows is -
OAuth 2.0
Page | 122
There are cases when we need to generate an access token for a user session. This access token performs various
transactions and helps maintain the user session. While using OAuth 2.0 you need to directly pass the access token
generated when the user login using the below syntax-
Using the access token you can easily request any of the resources secured using the OAuth scheme.
Now you may identify the types of authentication used in your web application. Similarly, you can use the
corresponding authentication scheme to make full use of rest assured capabilities.
The *PUT method *(HTTP PUT request method) creates a new resource or updates (substitutes) a representation of
the target resource with the request payload. This means a Put request updates a resource at a specified URI. It is
also used to create a new resource at the given URI or replace the entire product entity.
o In case a file or a resource already exists at that URI, the PUT method replaces that file or resource.
Let us now discuss the main differences between a PUT and a POST request.
PUT POST
This method is idempotent. This means it will produce the This method is not idempotent. It produces different
same results if executed more than once. results every time it is executed.
When we need to modify a single resource that is already POST method is called when a child resource is to be
part of resource collection, we call the PUT method. added under resources collection.
Page | 123
PUT POST
PUT method syntax : PUT /questions/{question-id} POST method syntax: POST /questions
Put method makes use of the "UPDATE" query. POST method makes use of the "CREATE" query.
In the PUT method, the client decides which URI resource In the POST method, the server decides which URI
should have. resource should have.
The methods POST and PUT use the following status codes:
POST request
PUT request
Now we'll demonstrate the PUT request using Swagger UI. The URL for the PUT request is given
here https://demoqa.com/BookStore/v1/Books/
Page | 124
In the above screen, we a trying to update a book record with ISBN="9781449325862". The two parameters that we
will update are userId: "toolsqa_test" and ISBN: "9781449325865". When we execute this put request we get the
following output.
We can see the status code 200 which we received from the server indicating the request was successful.
In the next section, we will implement the PUT request using Rest Assured.
As explained in the tutorial on a *POST request, to create JSON objects, we will add a Simple JSON* library in the
classpath in the code. Once this is done, we follow the below-given steps to put a request using REST Assured.
We will use the same URL for implementing the PUT request using Rest Assured.
Endpoint: https://demoqa.com/BookStore/v1/Books/
The first step is to create a JSON data request that we need to send using the "put()" method. The following piece of
code achieves this.
String token =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyTmFtZSI6InRlc3RpbmcxMjMiLCJwYXNzd29yZCI6IlBhc3N3b3JkQDEiL
CJpYXQiOjE2Mjg1NjQyMjF9.lW8JJvJF7jKebbqPiHOBGtCAus8D9Nv1BK6IoIIMJQ4";
Page | 125
String isbn = "9781449325865";
In the above code, we have used an ISBN parameter. Note that we already have a record with this ISBN. We will
update this record by sending the PUT request. So for this ISBN, we will update the record with a new ISBN and a
userId. We set a new value for the ISBN and also updated userId. So when we send this request, the record having
ISBN="9781449325862" will have its userId="toolsqa_test" and ISBN updated to the new value, "9781449325865".
java Response res = httpRequest.body("{ "isbn": "" + isbn + "", "userId": "" + userId + ""}")
.put("/BookStore/v1/Book/9781449325862");
So in the above code, we have created a request body as a JSON string and then we call the "put()" method with this
request by sending the ISBN as an argument. This ensures the record with the given ISBN is updated.
The next step is to validate the response to ensure record updation. This is done by reading the status code of the
response as follows:
Assert.assertEquals(res.getStatusCode(),200);
We have used the getStatusCode () method that returns the status code of the response. The value 200 indicates the
PUT request was successful. The execution of the above tests gives the following response:
The complete code for the PUT request demonstration using Rest Assured is as follows:
public class PUTMethod { String userId= "toolsqa_test"; String baseUrl="https://demoqa.com"; String token =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyTmFtZSI6InRlc3RpbmcxMjMiLCJwYXNzd29yZCI6IlBhc3N3b3JkQDEiL
CJpYXQiOjE2Mjg1NjQyMjF9.lW8JJvJF7jKebbqPiHOBGtCAus8D9Nv1BK6IoIIMJQ4"; String isbn ="9781449325865";
@Test
Page | 126
public void updateBook() {
RestAssured.baseURI = baseUrl;
.header("Content-Type", "application/json");
Response res = httpRequest.body("{ \"isbn\": \"" + isbn + "\", \"userId\": \"" + userId +
"\"}").put("/BookStore/v1/Book/9781449325862");
//Fetching the response code from the request and validating the same
Assert.assertEquals(res.getStatusCode(),200);
The steps discussed above demonstrate the basic working of a PUT request and how it differs from a POST request.
We used the JSON library to create JSON data sent in the content of the body of the request. We then validate the
response using the status code after obtaining the response.
An HTTP delete request is performed using the HTTP delete method (written as delete) which deletes a resource
from the server identified by the URI we are sending through it. Also note that a delete method intends to change
the state of the server. Although even a 200 code does not guarantee this. A few major points as highlighted in the
official HTTP RFC with respect to the delete request method are listed below-
• The Delete method requests the server to delete the resource identified by the request URI.
• The resource deletion depends on the server and is deleted if prescribed for deletion. Additionally, the
restoration implementation of the resource is also considerable.
• There is a deletion request for association between the resource and corresponding current functionality.
Page | 127
• It is similar to the rm UNIX command, where the current association of the resource is deleted instead of the
previous ones(if any).
• Delete request method is placed under the idempotent category of the W3C documentation. It means that
once a resource is requested for deletion, a request on the same resource again would give the same result as
the resource has already been deleted.
• Delete method response is non-cacheable. The user cannot cache the server response for later use. Caching a
delete request creates inconsistencies.
On sending the Delete request, the server responds with some response codes which signify the action performed by
the Delete method. Consider the following code for the same-
• 202(Accepted): The server accepts the request but does not enact.
• 204(No Content)- A status code of 204 on the HTTP delete request method denotes successful enactment of
the delete request without any content in the response.
• 200(OK)- The action was successful and the response message includes representation with the status.
• 404(Not Found) - When the server can't find the resource. The reason could either does not exist or previously
deleted.
Now that we understand the basics of the Delete method we will see how we can send a Delete request using rest
assured but before that let us see a simple DELETE request using Swagger UI. The URL for the request is-
https://demoqa.com/swagger/
Now you will have to select the first "Delete" in the BookStore section from this page.
Page | 128
Note: We have disabled the UserID to prevent an empty database. In practical application, you have to pass the
required values to the server.
When you will click on the section, you will see a response depicting that the execution was a success. A specific
response is received for cases like "bookid not found" or "user not found". See the snapshot below for more clarity-
In the introduction, we defined the delete method as something that can delete a resource. As a reminder, you can
relate the "resource" with the pet record here. A generic term "resource" denotes varying resources in various
requests. Now that we have seen how we may go about manually deleting a resource using swagger next we will try
to automate the Delete request using Rest Assured.
We will now see how we can delete a resource from the server using rest assured. To do so, we will use BookStore
APIs which we have been using in our previous examples. We will be automating the following use case-
1. Get a list of available books for to a user using the Get User Data API.
2. Delete a book corresponding to a specific ISBN and validate the response code using the Delete Book API.
3. Verify that the execution of API from step 1 updates the book list and does not display the deleted book.
Let us now see the code for the above use case using Rest Assured.
package bookstore;
import org.testng.Assert;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import io.restassured.response.ResponseBody;
import io.restassured.specification.RequestSpecification;
Page | 129
String userId= "de5d75d1-59b4-487e-b632-f18bc0665c0d";
String baseUrl="https://demoqa.com/swagger/";
String token =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyTmFtZSI6InRlc3RpbmcxMjMiLCJwYXNzd29yZCI6IlBhc3N3b3JkQDEiL
CJpYXQiOjE2Mjg1NjQyMjF9.lW8JJvJF7jKebbqPiHOBGtCAus8D9Nv1BK6IoIIMJQ4";
@BeforeTest
@AfterTest
RestAssured.baseURI = baseUrl;
RequestSpecification httpRequest =
.header("Content-Type", "application/json");
@Test
RestAssured.baseURI = baseUrl;
.header("Content-Type", "application/json");
Response res = httpRequest.body("{ \"isbn\": \"" + isbn + "\", \"userId\": \"" + userId +
"\"}").delete("/BookStore/v1/Book");
//Fetching the response code from the request and validating the same
Assert.assertEquals(res.getStatusCode(),204); }
}
Page | 130
Code walkthrough
Let's walk through the above code and see what we tried to achieve here. Note that the first method, i.e
getUserData() is a simple GET method where we are trying to fetch the user data corresponding to a userId. You may
refer to our article on Rest API using Rest Assured to understand the code if you have not gone through it yet.
Additionally, you will notice the authorization field. For this particular tutorial on the delete request method, you
need not worry about it. However, if you want to learn about authorization and OAuth 2.0, you can refer to our
other tutorials. In this tutorial about the delete method, we will go through the code written
under deleteBook() method here.
RestAssured.baseURI = baseUrl;
.header("Content-Type", "application/json");
We first set up the request with the base URI. Next, we add the header(s) which also include the Authorization token
using the RequestSpecification interface.
Response res = httpRequest.body("{ \"isbn\": \"" + isbn + "\", \"userId\": \"" + userId +
"\"}").delete("/BookStore/v1/Book");
Next, store the Response object using the RequestSpecification object. Here we are passing the JSON body of our
request along with the endpoint URL for the Delete method. The response gets store in a variable.
Assert.assertEquals(res.getStatusCode(),204);
Lastly, we are simply printing the response status code and using the TestNG Assert to validate the same. Since in
our case the expected response code is 204, our test would have it as the expected parameter.
Once you execute the code you will see that the getUserData method executes first, followed by the deleteBook
method. And then finally the getUserData method runs again. This is because we used
the @BeforeTest and @AfterTest for the getUserData method. The console would show you the result as below-
And there you go! You have successfully deleted a record from the user data using the Delete API. Now you may go
ahead and try out the different API methods using Rest Assured and strengthen your concepts. In our next post, we
will see how Basic Auth handles Rest Assured.
Page | 131
What is JSON?
JSON is one of the most used Data-Exchange format. It is a light weight format represented as pure text. Due to the
ability of almost all the languages to parse text, Json becomes independent of the programming language.
What is JSON?
JSON stands for JavaScript Object Notation. JSON is a human and machine-readable format to represent data
as Structured Data. JSON is used primarily to transfer data from one computer to another or even between different
programs on the same computer.
To visualize JSON, let us say that we want to represent a Person with following details in JSON
• Age = 34
• Profession = Engineer
"FirstName" : "Virender",
"LastName" : "Singh",
"Age" : 34,
"Profession": "Engineer"
At this point, we do not know the details of the JSON structure but we can still figure out what is being presented
in JSON . Let us now understand different elements used in JSON .
Key-Value Pairs
Key-Value pairs in JSON are used to represent a property of the Object. In the above example, we tried to represent
a Person. This person has some properties like
• First Name
• Last Name
• Age
• Profession
Each of these properties have a value associated with it. For e.g First Name has a value of Virender.
Similarly, Age has a value of 34. To write a Key-Value in JSON we have to follow these rules
From the above example, a Key-Value pair is FirstName. Try to find other Key-Value pairs yourself
"FirstName" : "Virender"
Page | 132
Values can be of following data types
Object in JSON
In JSON an object is represented by a collection of Key-Value pairs. This collection of Key-Value pairs are grouped
using { } (opening and closing curly braces}. Rules to writing an Object are
An example here is the Person Object, discussed above. The Person object follows the rules mentioned for
representing an Object
"FirstName" : "Virender",
"LastName" : "Singh",
"Age" : 34,
"Profession": "Engineer"
Array in JSON
Arrays are similar to Arrays that you know from any other programming language. In JSON an Array is collection of
Values separated by Comma. Here are the rules to write an Array
To understand an Array let us add one more property to the Person Object. Let us add hobby also, a Person can have
multiple hobbies. This makes it suitable to represent hobbies as an Array. As shown in the JSON below
"FirstName" : "Virender",
"LastName" : "Singh",
"Age" : 34,
"Profession": "Engineer",
Page | 133
See how multiple hobbies are represented using an Array. Array starts and ends with [ ] and contains values
separated by ,
These are the different components of a JSON , using these components we can create complex JSON . As a small
exercise for you, try to decode the JSON below and identify different structures involved in it.
"Description": "Map containing Country, Capital, Currency, and some States of that Country",
"Region": "Asia",
"Countries": [
"Country": "India",
"Data": {
"Currency": "Rupee"
},
"Country": "Nepal",
"Data": {
"Capital": "Katmandu",
In this tutorial, we will learn more about JSONPath and Query JSON using JSONPath. We will be covering the
following topic:
• What is JSONPath?
Page | 134
• How to Query JSON with JSONPath?
What is JSONPath?
Every JSON object is composed on an inherent hierarchy and structure. Every JSON ends up creating a tree of nodes,
where each node is a JSON Element. Let us take an example here, below is a simple JSON expressing a collection of
countries
"Description": "Map containing Country, Capital, Currency, and some States of that Country",
"Region": "Asia",
"Countries": [
"Country": "India",
"Data": {
"mintemp": 6,
"maxtemp": 45,
"Currency": "Rupee"
},
"Country": "Nepal",
"Data": {
"Capital": "Katmandu",
"mintemp": 9,
"maxtemp": 23,
At the top most level we have a Root node, which is basically the node containing all of the current JSON. Inside this
root node, we have following nodes
• Description
• Region
•
Countries
Page | 135
Description and Region are simple leaf nodes in the tree. But Countries is a non-leaf node, which further contains
more nodes. Here Countries node contains an array of two countries. If we were to simply define a hierarchical
relation between the Root node and any node in the JSON we can do like shown below.
Note: Let us represent Root node by $ and a relationship from parent to child with >>
Similarly, we can also define a relationship between the Root node and the zero'th item in the Countries array.
Relationship will be $ >> Countries[0] where [ ] is the index operator to represent an item at n index in an Array
of Countries.
In a way this hierarchy in JSON allows us to create a standard mechanism to traverse through specific parts of
the JSON. A standard way to do this is called JSONPath.
JSONPath creates a uniform standard and syntax to define different parts of a JSON document. JSONPath defines
expressions to traverse through a JSON document to reach to a subset of the JSON. This topic is best understood by
seeing it in action. We have created a web page which can help you evaluate a JSONPath. Use this page to practice
writing JSONPath. This is the link to JSONPath evaluator.
Root node operator in JSON is represented by a $ sign. $ will return all the nodes inside the JSON document. To try
this out open the JSONPath evaluator page and type $ in the JSONPath field. As shown in the image below
In order to get children of a given node, we can use the Dot (.) operator or the ['childname'] operator. In order to
get all the Countries we can have JSONPath as
Page | 136
• $.Countries
• $['Countries']
Output will be
"Country": "India",
"Data": {
"mintemp": 6,
"maxtemp": 45,
"Currency": "Rupee"
},
"Country": "Nepal",
"Data": {
"Capital": "Katmandu",
"mintemp": 9,
"maxtemp": 23,
Wild card operator in JSONPath is (Star or Asterisk) symbol. This is literally means everything under that node. For
example, if you want to display the Data nodes of all the countries you can simple write following JSONPat
• $.Countries[].Data*
• $['Countries'][].Data*
Page | 137
"mintemp": 6,
"maxtemp": 45,
"Currency": "Rupee"
},
"Capital": "Katmandu",
"mintemp": 9,
"maxtemp": 23,
Sometimes it is required to access a particular entry at a given index in the JSON array. We can use the Array
Index [i,j,k... ] to identify an entry at a particular index. In the above example, let us find out the last Country entry
in the Countries array.
• $.Countries[-1]
• $['Countries'][-1]
Here -1 stands for the last item in the Array. You can also refer to the last item by giving a positive value to the index.
For e.g.
• $.Countries[1]
• $['Countries'][1]
"Country": "Nepal",
"Data": {
"Capital": "Katmandu",
"mintemp": 9,
"maxtemp": 23,
Note: Array index starts from 0. Hence to refer to the second item in the array we have to use 1 as the index.
Page | 138
Array index is just not limited to displaying only 1 item. We can extract multiple items from the array at different
indexes. The syntax to do so is [i,j,k..]. For e.g. to extract the first 2 array items we will write the JSONPath as
• $.Countries[0,1]
• $['Countries'][0,1]
Output will be
"Country": "India",
"Data": {
"mintemp": 6,
"maxtemp": 45,
"Currency": "Rupee"
},
"Country": "Nepal",
"Data": {
"Capital": "Katmandu",
"mintemp": 9,
"maxtemp": 23,
For the JsonPath shown below, we will change our Json to have more nodes. Let us take a look at
a Json representing collections of books. Here is the Json, from now on use this Json in the JsonPath Evaluator
"store": {
"book": [
"category": "reference",
Page | 139
"price": 8.95
},
"category": "fiction",
"price": 12.99
},
"category": "fiction",
"isbn": "0-553-21311-3",
"price": 8.99
},
"category": "fiction",
"isbn": "0-395-19395-8",
"price": 22.99
],
"bicycle": {
"color": "red",
"price": 19.95
},
"expensive": 10
Array slice operator is wonderful operator to extract selected items from Json. Taking the example of books, what if
we want to retrieve every alternative book in the Json. To do that we will need the Array, Slice operator. Syntax of
Array Slice operator is [StartIndex : EndIndex : Steps]. Let find out what are books at odd number in the books
collection. JsonPath will look like
Page | 140
• $..book[1,4,2]
• $..['book'][1,4,2]
"category": "fiction",
"price": 12.99
},
"category": "fiction",
"isbn": "0-553-21311-3",
"price": 8.99
Expressions in JSONPath
Usage of Expressions in JsonPath is a very good feature to have concise and complex JsonPaths. Expressions in
JsonPath are basically code snippets that evaluate to the Boolean value. Based on the outcome only the nodes which
meet the criteria are selected. Let us see more about it, but before that make sure you have gone through following
tutorials on basics of Json and JsonPath
• Json
• Jsonpath
In this tutorial, we will use a sample Json which has a few items in the Array. Please copy the below Json in
our JsonPath Evaluator
"books": [
"isbn": "9781593275846",
"published": "2014-12-14T00:00:00.000Z",
Page | 141
"publisher": "No Starch Press",
"pages": 472,
"description": "JavaScript lies at the heart of almost every modern web application, from social apps to the
newest browser-based games. Though simple for beginners to pick up and play with, JavaScript is a flexible, complex
language that you can use to build full-scale applications.",
"website": "https://eloquentjavascript.net/"
},
"isbn": "9781449331818",
"published": "2012-07-01T00:00:00.000Z",
"pages": 254,
"description": "With Learning JavaScript Design Patterns, you'll learn how to write beautiful, structured, and
maintainable JavaScript by applying classical and modern design patterns to the language. If you want to keep your
code efficient, more manageable, and up-to-date with the latest best practices, this book is for you.",
"website": "https://www.addyosmani.com/resources/essentialjsdesignpatterns/book/"
},
"isbn": "9781449365035",
"published": "2014-02-01T00:00:00.000Z",
"pages": 460,
"description": "Like it or not, JavaScript is everywhere these days-from browser to server to mobile-and now you,
too, need to learn the language or dive deeper than you have. This concise book guides you into and through
JavaScript, written by a veteran programmer who once found himself in the same position.",
"website": "https://speakingjs.com/"
},
"isbn": "9781491950296",
"published": "2014-07-01T00:00:00.000Z",
"pages": 254,
"description": "Take advantage of JavaScript's power to build robust web-scale or enterprise applications that are
easy to extend and maintain. By applying the design patterns outlined in this practical book, experienced JavaScript
developers will learn how to write flexible and resilient code that's easier-yes, easier-to work with as your code base
grows.",
"website": "https://chimera.labs.oreilly.com/books/1234000000262/index.html"
},
"isbn": "9781593277574",
"published": "2016-09-03T00:00:00.000Z",
"pages": 352,
"description": "ECMAScript 6 represents the biggest update to the core of JavaScript in the history of the
language. In Understanding ECMAScript 6, expert developer Nicholas C. Zakas provides a complete guide to the
object types, syntax, and other exciting changes that ECMAScript 6 brings to JavaScript.",
"website": "https://leanpub.com/understandinges6/read"
},
"isbn": "9781491904244",
"published": "2015-12-27T00:00:00.000Z",
"pages": 278,
"description": "No matter how much experience you have with JavaScript, odds are you don’t fully understand
the language. As part of the 'You Don’t Know JS' series, this compact guide focuses on new features available in
ECMAScript 6 (ES6), the latest version of the standard upon which JavaScript is built.",
"website": "https://github.com/getify/You-Dont-Know-JS/tree/master/es6%20&%20beyond"
Page | 143
},
"isbn": "9781449325862",
"published": "2013-08-02T00:00:00.000Z",
"pages": 234,
"description": "This pocket guide is the perfect on-the-job companion to Git, the distributed version control
system. It provides a compact, readable introduction to Git for new users, as well as a reference to common
commands and procedures for those of you with Git experience.",
"website": "https://chimera.labs.oreilly.com/books/1230000000561/index.html"
},
"isbn": "9781449337711",
"published": "2014-04-07T00:00:00.000Z",
"pages": 538,
"description": "Design and build Web APIs for a broad range of clients—including browsers and mobile devices—
that can adapt to change over time. This practical, hands-on guide takes you through the theory and tools you need
to build evolvable HTTP services with Microsoft’s ASP.NET Web API framework. In the process, you’ll learn how
design and implement a real-world Web API.",
"website": "https://chimera.labs.oreilly.com/books/1234000001708/index.html"
Expressions in JsonPath
Expressions in JsonPath are one of the most powerful features of JsonPath. Note that expressions are also available
in Xpath and CSS Selectors. Expressions help you create a condition that is evaluated to true or false. There are two
important symbols that you have to understand before you can create Expressions in JsonPath.
• @ : At symbol, signifies the current node being processed. Syntax used $.books[?(@.price > 100)]
Page | 144
Let us now take a simple task from the Json above.
• Find out all the books which have the pages greater than 460
To create a JsonPath which can get us all the books which have pages greater than 460, we have to break the
problem into two parts
2. Append an expression to filter all the books which have pages greater than 460
To get all the books we can create a simple JsonPath: $.books . Now we have to add an expression in the array
books. To do so we will simple start an expression with***?*** sign and then add a filter on the current node @ . A
simple expression will look like this ?(@.pages > 460).
If we combine JsonPath with the expression we will get this: $.books[?(@.pages > 460)]
In the JsonPath Evaluator, simply enter this expression and see the results. As shown in the image below
The result will be all the books with page numbers greater than 460. Here is the result Json
"isbn": "9781593275846",
"published": "2014-12-14T00:00:00.000Z",
Page | 145
"publisher": "No Starch Press",
"pages": 472,
"description": "JavaScript lies at the heart of almost every modern web application, from social apps to the newest
browser-based games. Though simple for beginners to pick up and play with, JavaScript is a flexible, complex
language that you can use to build full-scale applications.",
"website": "https://eloquentjavascript.net/"
},
"isbn": "9781449337711",
"published": "2014-04-07T00:00:00.000Z",
"pages": 538,
"description": "Design and build Web APIs for a broad range of clients—including browsers and mobile devices—
that can adapt to change over time. This practical, hands-on guide takes you through the theory and tools you need
to build evolvable HTTP services with Microsoft’s ASP.NET Web API framework. In the process, you’ll learn how
design and implement a real-world Web API.",
"website": "https://chimera.labs.oreilly.com/books/1234000001708/index.html"
Just like any programming language, JsonPath supports all the logical operators. Below is the list of Logical Operators
that we can use to create expressions. Every logical operator is discussed in detail below.
Operator Description
Try all the above examples and also try to create more expressions based on your needs. This way you will learn
more about the JsonPath expressions.
Page | 146
As the name suggests the operator checks if the left-hand side is equal to the right-hand side. Let us find out all the
books that have 352 pages. Here is the JsonPath
"isbn": "9781593277574",
"published": "2016-09-03T00:00:00.000Z",
"pages": 352,
"description": "ECMAScript 6 represents the biggest update to the core of JavaScript in the history of the language.
In Understanding ECMAScript 6, expert developer Nicholas C. Zakas provides a complete guide to the object types,
syntax, and other exciting changes that ECMAScript 6 brings to JavaScript.",
"website": "https://leanpub.com/understandinges6/read"
When we want to exclude a particular set of values based on a condition we use the not equal to operator. Let us
just invert the example above and find all the books that have page numbers not equal to 352.
"isbn": "9781593275846",
"published": "2014-12-14T00:00:00.000Z",
"pages": 472,
"description": "JavaScript lies at the heart of almost every modern web application, from social apps to the newest
browser-based games. Though simple for beginners to pick up and play with, JavaScript is a flexible, complex
language that you can use to build full-scale applications.",
Page | 147
"website": "https://eloquentjavascript.net/"
},
"isbn": "9781449331818",
"published": "2012-07-01T00:00:00.000Z",
"pages": 254,
"description": "With Learning JavaScript Design Patterns, you'll learn how to write beautiful, structured, and
maintainable JavaScript by applying classical and modern design patterns to the language. If you want to keep your
code efficient, more manageable, and up-to-date with the latest best practices, this book is for you.",
"website": "https://www.addyosmani.com/resources/essentialjsdesignpatterns/book/"
},
"isbn": "9781449365035",
"published": "2014-02-01T00:00:00.000Z",
"pages": 460,
"description": "Like it or not, JavaScript is everywhere these days-from browser to server to mobile-and now you,
too, need to learn the language or dive deeper than you have. This concise book guides you into and through
JavaScript, written by a veteran programmer who once found himself in the same position.",
"website": "https://speakingjs.com/"
},
"isbn": "9781491950296",
"subtitle": "Robust Web Architecture with Node, HTML5, and Modern JS Libraries",
"published": "2014-07-01T00:00:00.000Z",
Page | 148
"pages": 254,
"description": "Take advantage of JavaScript's power to build robust web-scale or enterprise applications that are
easy to extend and maintain. By applying the design patterns outlined in this practical book, experienced JavaScript
developers will learn how to write flexible and resilient code that's easier-yes, easier-to work with as your code base
grows.",
"website": "https://chimera.labs.oreilly.com/books/1234000000262/index.html"
},
"isbn": "9781491904244",
"published": "2015-12-27T00:00:00.000Z",
"pages": 278,
"description": "No matter how much experience you have with JavaScript, odds are you don’t fully understand the
language. As part of the 'You Don’t Know JS' series, this compact guide focuses on new features available in
ECMAScript 6 (ES6), the latest version of the standard upon which JavaScript is built.",
"website": "https://github.com/getify/You-Dont-Know-JS/tree/master/es6+&+beyond"
},
"isbn": "9781449325862",
"published": "2013-08-02T00:00:00.000Z",
"pages": 234,
"description": "This pocket guide is the perfect on-the-job companion to Git, the distributed version control
system. It provides a compact, readable introduction to Git for new users, as well as a reference to common
commands and procedures for those of you with Git experience.",
"website": "https://chimera.labs.oreilly.com/books/1230000000561/index.html"
},
"isbn": "9781449337711",
Page | 149
"subtitle": "Harnessing the Power of the Web",
"published": "2014-04-07T00:00:00.000Z",
"pages": 538,
"description": "Design and build Web APIs for a broad range of clients—including browsers and mobile devices—
that can adapt to change over time. This practical, hands-on guide takes you through the theory and tools you need
to build evolvable HTTP services with Microsoft’s ASP.NET Web API framework. In the process, you’ll learn how
design and implement a real-world Web API.",
"website": "https://chimera.labs.oreilly.com/books/1234000001708/index.html"
Less than operator, as the name suggests will return all the values that are less than the value given on the right. Let
us find out all the books with pages less than 352.
"isbn": "9781449331818",
"published": "2012-07-01T00:00:00.000Z",
"pages": 254,
"description": "With Learning JavaScript Design Patterns, you'll learn how to write beautiful, structured, and
maintainable JavaScript by applying classical and modern design patterns to the language. If you want to keep your
code efficient, more manageable, and up-to-date with the latest best practices, this book is for you.",
"website": "https://www.addyosmani.com/resources/essentialjsdesignpatterns/book/"
},
"isbn": "9781491950296",
"subtitle": "Robust Web Architecture with Node, HTML5, and Modern JS Libraries",
"pages": 254,
"description": "Take advantage of JavaScript's power to build robust web-scale or enterprise applications that are
easy to extend and maintain. By applying the design patterns outlined in this practical book, experienced JavaScript
developers will learn how to write flexible and resilient code that's easier-yes, easier-to work with as your code base
grows.",
"website": "https://chimera.labs.oreilly.com/books/1234000000262/index.html"
},
"isbn": "9781491904244",
"published": "2015-12-27T00:00:00.000Z",
"pages": 278,
"description": "No matter how much experience you have with JavaScript, odds are you don’t fully understand the
language. As part of the 'You Don’t Know JS' series, this compact guide focuses on new features available in
ECMAScript 6 (ES6), the latest version of the standard upon which JavaScript is built.",
"website": "https://github.com/getify/You-Dont-Know-JS/tree/master/es6+&+beyond"
},
"isbn": "9781449325862",
"published": "2013-08-02T00:00:00.000Z",
"pages": 234,
"description": "This pocket guide is the perfect on-the-job companion to Git, the distributed version control
system. It provides a compact, readable introduction to Git for new users, as well as a reference to common
commands and procedures for those of you with Git experience.",
"website": "https://chimera.labs.oreilly.com/books/1230000000561/index.html"
Page | 151
Less than equal to ( <= ) operator in JsonPath
This operator will let you get all the values that are less than or equal to a given value. Let us find out all the books
which have pages less than or equal to 352.
"isbn": "9781449331818",
"published": "2012-07-01T00:00:00.000Z",
"pages": 254,
"description": "With Learning JavaScript Design Patterns, you'll learn how to write beautiful, structured, and
maintainable JavaScript by applying classical and modern design patterns to the language. If you want to keep your
code efficient, more manageable, and up-to-date with the latest best practices, this book is for you.",
"website": "https://www.addyosmani.com/resources/essentialjsdesignpatterns/book/"
},
"isbn": "9781491950296",
"subtitle": "Robust Web Architecture with Node, HTML5, and Modern JS Libraries",
"published": "2014-07-01T00:00:00.000Z",
"pages": 254,
"description": "Take advantage of JavaScript's power to build robust web-scale or enterprise applications that are
easy to extend and maintain. By applying the design patterns outlined in this practical book, experienced JavaScript
developers will learn how to write flexible and resilient code that's easier-yes, easier-to work with as your code base
grows.",
"website": "https://chimera.labs.oreilly.com/books/1234000000262/index.html"
},
"isbn": "9781491904244",
"published": "2015-12-27T00:00:00.000Z",
"pages": 278,
"description": "No matter how much experience you have with JavaScript, odds are you don’t fully understand the
language. As part of the 'You Don’t Know JS' series, this compact guide focuses on new features available in
ECMAScript 6 (ES6), the latest version of the standard upon which JavaScript is built.",
"website": "https://github.com/getify/You-Dont-Know-JS/tree/master/es6+&+beyond"
},
"isbn": "9781449325862",
"published": "2013-08-02T00:00:00.000Z",
"pages": 234,
"description": "This pocket guide is the perfect on-the-job companion to Git, the distributed version control
system. It provides a compact, readable introduction to Git for new users, as well as a reference to common
commands and procedures for those of you with Git experience.",
"website": "https://chimera.labs.oreilly.com/books/1230000000561/index.html"
Greater than operator will let you get all the values which are greater than the value on the left-hand side. Let us
find all the books which have pages more than 460.
"isbn": "9781593275846",
Page | 153
"published": "2014-12-14T00:00:00.000Z",
"pages": 472,
"description": "JavaScript lies at the heart of almost every modern web application, from social apps to the newest
browser-based games. Though simple for beginners to pick up and play with, JavaScript is a flexible, complex
language that you can use to build full-scale applications.",
"website": "https://eloquentjavascript.net/"
},
"isbn": "9781449337711",
"published": "2014-04-07T00:00:00.000Z",
"pages": 538,
"description": "Design and build Web APIs for a broad range of clients—including browsers and mobile devices—
that can adapt to change over time. This practical, hands-on guide takes you through the theory and tools you need
to build evolvable HTTP services with Microsoft’s ASP.NET Web API framework. In the process, you’ll learn how
design and implement a real-world Web API.",
"website": "https://chimera.labs.oreilly.com/books/1234000001708/index.html"
Greater than equal will let you get all the values that are equal to or greater than value on the right-hand side. Let's
get all the books with pages either greater than or equal to 460
"isbn" : "9781593275846",
"published" : "2014-12-14T00:00:00.000Z",
"description" : "JavaScript lies at the heart of almost every modern web application, from social apps to the
newest browser-based games. Though simple for beginners to pick up and play with, JavaScript is a flexible, complex
language that you can use to build full-scale applications.",
"website" : "https://eloquentjavascript.net/"
},
"isbn" : "9781449365035",
"published" : "2014-02-01T00:00:00.000Z",
"pages" : 460,
"description" : "Like it or not, JavaScript is everywhere these days-from browser to server to mobile-and now you,
too, need to learn the language or dive deeper than you have. This concise book guides you into and through
JavaScript, written by a veteran programmer who once found himself in the same position.",
"website" : "https://speakingjs.com/"
},
"isbn" : "9781449337711",
"published" : "2014-04-07T00:00:00.000Z",
"pages" : 538,
"description" : "Design and build Web APIs for a broad range of clients\u2014including browsers and mobile
devices\u2014that can adapt to change over time. This practical, hands-on guide takes you through the theory and
tools you need to build evolvable HTTP services with Microsoft\u2019s ASP.NET Web API framework. In the process,
you\u2019ll learn how design and implement a real-world Web API.",
"website" : "https://chimera.labs.oreilly.com/books/1234000001708/index.html"
Page | 155
Deserialize JSON Array to List
In this tutorial we will talk about the advance usage of JSONPath in Rest Assured which is How to DeSerialize JSON
Array to List. If you have reached here directly, I would suggest that you go through these links before starting with
this.
Earlier we saw how JSONPath can be used to make a deterministic and accurate search in the Response JSON. With
this capability, we are able to write better test validations.
In this chapter, we will focus on how we can perform an advance search in the Response JSON by Deserialize JSON
Array to List. We will also learn how we can represent the searched section of Response in various Java data
structures. This tutorial is structured based on different methods available in JSONPath class.
JsonPath class has two overloaded methods (jsonPath.getList) to extract JSON nodes as a Java List. Here are the
methods
• JsonPath.getList(String, Class T) method let us get the searched nodes as a List of T type
To understand JsonPath.getList(String) method we will try to retrieve all the books as a List of
String (List<String>). All we need to do is give "books" as the JSONPath.
@Test
RestAssured.baseURI = "https://restapi.demoqa.com/utilities/books/getallbooks";
Page | 156
RequestSpecification httpRequest = RestAssured.given();
// First get the JsonPath object instance from the Response interface
// Read all the books as a List of String. Each item in the list
Once you run this, the output will be look like this:
We all are familiar with Serialization and De-serialization support built-in in Rest-Assured. Let us try to convert the
searched nodes directly into an object representation. In this example let us retrieve all the books from
the JSON response. We will retrieve all the books as a List of Books class. In order to do this, we will first create
a Class Representation of a Book. Get all the properties of JSON Book entity and create a class with those member
variables. A book can be simply represented by a POJO class as shown in the code below.
String isbn;
String title;
Page | 157
String subtitle;
String author;
String published;
String publisher;
int pages;
String description;
String website;
Now to get the response converted into a List of Books we will simply use the JsonPath.getList(String, Class T)
method.
• Second parameter is the Type name to which we want the response to be converted. Book class in this case.
@Test
RestAssured.baseURI = "https://restapi.demoqa.com/utilities/books/getallbooks";
// First get the JsonPath object instance from the Response interface
// Read all the books as a List of String. Each item in the list
// Note that every book entry in the list will be complete Json object of book
Page | 158
}
This is a very good feature of Rest-Assured that enables us to get a targeted part of the response.
This tutorial further builds upon our understanding of Deserialization of a JSON Response into an object of a given
Type. Please go through the basics of Serialization and Deserialization in the below tutorial
"books": [
"isbn": "9781593275846",
"published": "2014-12-14T00:00:00.000Z",
"pages": 472,
"description": "JavaScript lies at the heart of almost every modern web application, from social apps to the
newest browser-based games. Though simple for beginners to pick up and play with, JavaScript is a flexible, complex
language that you can use to build full-scale applications.",
"website": "https:\/\/fanyv88.com:443\/http\/eloquentjavascript.net\/"
},
"isbn": "9781449331818",
"published": "2012-07-01T00:00:00.000Z",
Page | 159
"publisher": "O'Reilly Media",
"pages": 254,
"description": "With Learning JavaScript Design Patterns, you'll learn how to write beautiful, structured, and
maintainable JavaScript by applying classical and modern design patterns to the language. If you want to keep your
code efficient, more manageable, and up-to-date with the latest best practices, this book is for you.",
"website": "https:\/\/fanyv88.com:443\/http\/www.addyosmani.com\/resources\/essentialjsdesignpatterns\/book\/"
},
"isbn": "9781449365035",
"published": "2014-02-01T00:00:00.000Z",
"pages": 460,
"description": "Like it or not, JavaScript is everywhere these days-from browser to server to mobile-and now
you, too, need to learn the language or dive deeper than you have. This concise book guides you into and through
JavaScript, written by a veteran programmer who once found himself in the same position.",
"website": "https:\/\/fanyv88.com:443\/http\/speakingjs.com\/"
},
"isbn": "9781491950296",
"subtitle": "Robust Web Architecture with Node, HTML5, and Modern JS Libraries",
"published": "2014-07-01T00:00:00.000Z",
"pages": 254,
"description": "Take advantage of JavaScript's power to build robust web-scale or enterprise applications that
are easy to extend and maintain. By applying the design patterns outlined in this practical book, experienced
JavaScript developers will learn how to write flexible and resilient code that's easier-yes, easier-to work with as your
code base grows.",
"website": "https:\/\/fanyv88.com:443\/http\/chimera.labs.oreilly.com\/books\/1234000000262\/index.html"
},
"isbn": "9781593277574",
Page | 160
"title": "Understanding ECMAScript 6",
"published": "2016-09-03T00:00:00.000Z",
"pages": 352,
"description": "ECMAScript 6 represents the biggest update to the core of JavaScript in the history of the
language. In Understanding ECMAScript 6, expert developer Nicholas C. Zakas provides a complete guide to the
object types, syntax, and other exciting changes that ECMAScript 6 brings to JavaScript.",
"website": "https:\/\/fanyv88.com:443\/https\/leanpub.com\/understandinges6\/read"
},
"isbn": "9781491904244",
"published": "2015-12-27T00:00:00.000Z",
"pages": 278,
"description": "No matter how much experience you have with JavaScript, odds are you don\u2019t fully
understand the language. As part of the 'You Don\u2019t Know JS' series, this compact guide focuses on new
features available in ECMAScript 6 (ES6), the latest version of the standard upon which JavaScript is built.",
"website": "https:\/\/fanyv88.com:443\/https\/github.com\/getify\/You-Dont-Know-JS\/tree\/master\/es6%20&%20beyond"
},
"isbn": "9781449325862",
"published": "2013-08-02T00:00:00.000Z",
"pages": 234,
"description": "This pocket guide is the perfect on-the-job companion to Git, the distributed version control
system. It provides a compact, readable introduction to Git for new users, as well as a reference to common
commands and procedures for those of you with Git experience.",
"website": "https:\/\/fanyv88.com:443\/http\/chimera.labs.oreilly.com\/books\/1230000000561\/index.html"
Page | 161
},
"isbn": "9781449337711",
"published": "2014-04-07T00:00:00.000Z",
"pages": 538,
"description": "Design and build Web APIs for a broad range of clients\u2014including browsers and mobile
devices\u2014that can adapt to change over time. This practical, hands-on guide takes you through the theory and
tools you need to build evolvable HTTP services with Microsoft\u2019s ASP.NET Web API framework. In the process,
you\u2019ll learn how design and implement a real-world Web API.",
"website": "https:\/\/fanyv88.com:443\/http\/chimera.labs.oreilly.com\/books\/1234000001708\/index.html"
This JSON Response contains an Array of Books. Each item in the JSON Array represents a book and has properties of
a book like "isbn", "title", "author" etc. In the earlier tutorial, we learnt How to Deserialize JSON Resposne of Single
Node to an Instance of Class. However, in Deserializing a Collection of Nodes into Array becomes little tricky. Let us
see how Rest Assured helps us achieve this quickly and without writing any boilerplate code.
Similarly, we can convert a Json Array into a Java Array. JsonPath class has method called getObject. This method
can be used to convert the response directly into a Java Array of Book. The only thing the we need to do is
pass Book[].class as the second argument to the method to signify that we want the Json to be deserialized into an
Array of Book. Here is the code that will do this
@Test
RestAssured.baseURI = "https://restapi.demoqa.com/utilities/books/getallbooks";
// We can convert the Json Response directly into a Java Array by using
Page | 162
// JsonPath.getObject method. Here we have to specify that we want to
// deserialize the Json into an Array of Book. This can be done by specifying
The above two techniques are important to write Concise test code. Apart from writing concise tests by using the
above techniques we fully utilize the features given to us by Rest-Assured. This helps us have lesser dependencies
outside Rest Assured and also enables us to write reliable tests.
The old practice of having only the GUI tests for automation does not exist anymore. Moreover, the problems in
software testing with the GUI tests are several. To enumerate a few:
In a two week aligned sprint, it gets altogether challenging to have a UI ready and test it simultaneously for test
coverage results. Unlike the GUI tests, the API testing doesn't rely on the UI. It becomes much more comfortable to
conjoin/ integrate them under Agile Development. Additionally, it can be brought in much earlier at the
development stage. The increasing/ rising trend of API Testing underlines this further.
An API abstracts the implementation layer, exposing only the objects needed by the developer. It consists
of REST methods. Moreover, these REST methods fetch, manipulate, and delete the data in the application's
database. We need to familiarize ourselves with the workings of REST API basics. Please go through the REST
API tutorials to be acquainted with those.
Once we have familiarised ourselves with the REST API basics, it is time to learn to test the REST APIs. To test a REST
API, we must understand the interface of the API. This includes:
• Structure of responses
Page | 163
Therefore, an essential step in that direction would be to look at the API Documentations. In this article, we are
going to cover:-
Documentation of any technology has a direct impact on the adoption and its usage. Without the knowledge of the
tool, no one would know how to use it. Moreover, there are other advantages to it as listed below:
These are some of the benefits of API documentation. Let us learn and understand what all consists of an API
Documentation.
API documents are similar to a reference manual. It talks about the necessary information of an API, in terms of,
Description of Resources
The data returned by the API are resources. Various endpoints can be used to access resources. Under the same
resource, an API will have several routes grouped. Resources and endpoint descriptions are generally short and
precise. Additionally, the user guide contains a piece of more detailed information.
The endpoint is an essential part of the API documentation. The developers implement it to make the requests.
Endpoints indicate ways to access resources. The methods indicate permissible interactions such as GET, PUT, POST,
or DELETE with the resource. Endpoints, similar to overall resource descriptions, as well have short brief
descriptions. The endpoint shows the end path of a resource. It does not include a common base path to all
endpoints.
Consider a sample APIs collection available to us as TOOLSQA - Bookstore API provided by TOOLSQA. Please
navigate to the URL. Consequently, once the page opens, we will see this:
Page | 164
In the above image:
An HTTP method acts as a verb. The listed verbs POST, GET, DELETE in the above image are some of the examples.
Moreover, there are others as well, like PUT, PATCH, OPTION, etc.
1. /Account/v1/Authorized
2. /Account/v1/GenerateToken
3. /Account/v1/User
4. /Account/v1/User/{GUID}
5. /Account/v1/User/{UserId}
6. /BookStore/v1/Books
7. /BookStore/v1/Books
The routes are following the method to form an endpoint. Example, GET /Account/v1/Authorized.
Note: We have a very few endpoints listed here in the sample bookstore API URL. But in actual projects, the list of
endpoints can be much large.
For an endpoint, the full resource URL needn't be listed in an API document. So, in our example, GET
/Account/v1/Authorized is listed instead of GET http://bookstore.toolsqa.com/Account/v1/Authorized
It is done with the thought to make the users focus on the path. Additionally, the user guide provides the full
resource URL and the needed authorization in the introductory section.
Parameters used
Parameters are the options that control the resource. There are four kinds of parameters:
1. Header parameter: As the name suggests, these are the parameters passed into the request headers. They
are generally related to the authorization and included under a separate section of authorization
Page | 165
requirements for standard header parameters. Additionally, in the case of unique parameters passed in the
headers, they are documented with the respective endpoint.
2. Path parameter: Path parameters are part of the endpoint. They are not optional. We usually write them
along with curly braces. For example, /Account/v1/User/{UserId} Here, {UserId} is the path parameter.
3. Query parameter: They are attached to the URL end. Additionally, the Query Parameter is appended to the
URL after adding '?' at the end of the URL. You can read more in the Query Parameter tutorial.
4. Request body parameters: In a POST request, several times, a JSON object is submitted in the request body.
Moreover, it is a list of key-value pairs.
Example:
"username": "TOOLSQA-Test",
"password": "Test@@123"
Page | 166
In the above example, we passed the username and password as request body parameters. We got a 200 status
code response along with the response body for the POST request of the endpoint /Account/v1/GenerateToken, we
sent.
Thus, we have understood the contents of a typical API document. An API document may contain additional
information. But the above part of the tutorial gives us a general idea of everything included under an API document.
Subsequently, in our next stage, we will learn the usage of an API document.
To understand the use of Swagger API documentation, we will use the same Bookstore API used previously. It
consists of a sandbox environment that tests the APIs on the documentation.
• Account
• BookStore
Some of those API Endpoints listed below build our End to End Rest API Framework. Please try these examples once
you have learned to use the API document at the end of this section.
Page | 167
HTTP VERB Route PURPOSE
We listed some of the APIs below from the bookstore API. They will help us to understand the requests and their
response bodies using Swagger.
1. To Create User
Before we begin exploring the APIs, we need to create a user with a username and password. Subsequently, add a
desired username and password under Book Store Credentials.
Note: Please choose your username and password, and once created, remember to use the same username and
password for all the tests. For example, throughout we will be using TOOLSQA-Test as username and Test@@123 as
password.
Now, let's try and create a userID using the POST Request for User.
Make a request
1. First, Expand the POST method for the endpoint under Account: /Account/v1/User
2. Second, click the Try it out button. The Request Body field gets editable.
3. Third, add the username and password. You have added now, as indicated in the below screenshot. After
that, select the parameter content type as application/json. Click on the Execute button.
4. Finally, Swagger submits the request. It shows the curl that was submitted. The Response, for the request, is
observed in the response section.
Page | 168
Note: Please note down the userID. You will need it for other APIs in the request body.
Explanation: We passed a POST Request with username and password in JSON format. We got a 201 status
code along with userID, and books associated with the respective username in the Response body. It explains that
our request was successfully sent over the server, as you can see in the above image under Description. Additionally,
Swagger's implementation is simple and useful. It provides an interactive experience to send a request and receive a
response for APIs.
As software professionals, we need to understand the underpinnings on which great software builds. One of the
many means is to try and test them over in various ways. We familiarized ourselves with the API Documentation.
Additionally, Swagger provided us with the means to test it on Swagger UI itself.
Now that we have created a user in our previous response let's try and create a token using the POST Request for
User.
Page | 169
Explanation: We sent our request with the body containing a username and password in
the application/json format. When we click the Execute button, we got a 200 status code. Additionally, we also got a
response body with the token, expires, status, and result fields. In the next section, we will understand the context
of API tests and study its various types.
Before we commence actual testing of the APIs, we need to compile associated information of the APIs. The context
in which we carry out testing is essential because it drives our testing efforts.
Below is a non-comprehensive list of the information we can seek before we start testing the APIs:
• Fields to be validated
• Parameters required
Let us understand, under which all categories the API tests can be divided. It is not to say that we have enlisted a
comprehensive list; there could be more types we can add to the list. But more or less, the API tests fall under one of
the categories mentioned below.
Page | 170
1. Validation Testing: It forms one of the last segments in the software development process. It caters to the
testing explicitly done to assess the product; its behavior, and its efficiency. The API is examined for
correctness in implementation as per the expectations. Additionally, the API is also verified based on pre-
established agreed-upon criteria such as the delivery of specific end goals, integration with the specified
environment. In addition to that, the testing of API's behavior to access the correct data happens as a part of
Validation testing.
2. Functional Testing: This is one of the broader types of testing. It aims to test specified functions. While
testing the APIs for functional testing, the assessment of the responses received happens against expected
responses in terms of passing parameters. Additionally, the error handling for unsuccessful requests and
invalid responses too are under consideration under these tests. The boundary cases, along with regular
tests, fall under the scope of these tests.
3. UI Testing: UI Tests tend to be more specific. These tests assess the user interface against the APIs and their
constituent parts. Additionally, the tests are more generalized with a focus on the API health; it's usability as
well as compatibility of the front end and back end.
4. Load Testing: This test is for the functionality and performance of the APIs under load. The API undergoes
theoretical regular traffic. The test results form the baseline to conduct further load testing. Additionally, the
testing also includes subjecting the API to maximum possible traffic to test the behavior of the API under full
loads. APIs undergo overloading tests. In this test, the verification of the API performance and error handling
conditions during failure happens.
5. Error Detection: The tests for APIs, which include the monitoring, inducing execution errors, sending invalid
requests, detecting operational leaks, etc. fall under this category. The introduction of known failure
scenarios in the APIs happens. The testing of these APIs happens to ensure that the errors are detected,
handled as well as routed.
6. API Security tests: Specific tests verify the APIs performance for vulnerabilities from external threats. Security
testing, Penetration testing, and Fuzz testing are some of them. For example, Security testing involves
validation of the APIs in terms of security requirements. Additionally, these security requirements could be
related to permissions, authorizations, authentications, etc. An authorized attack launches against the
system as a part of Penetration testing. It evaluates the security of the API. A full-scale assessment report of
strengths and weaknesses of the APIs is the deliverable issued after such a test. In Fuzz testing, evaluation of
API behavior happens. It is subjected to unexpected, invalid, and random data of enormous size. Following
this, the crashes, built-in assertions, and memory leaks are known.
7. Integration testing: The Integration tests focus on API communication with another module APIs.
8. Reliability testing: The API should display a prompt response for different configurations. It also looks for a
response data structure as a part of testing.
To conclude, in this post, we have got an understanding of API documentation. We learned to use the Swagger API
document. Additionally, we acquainted ourselves with types of API testing.
In further posts, we will learn to build REST API Automation Framework around the API tests. Try out using the API
document as guided above and reach out for your valuable feedback.
We carefully laid the foundations of our API automation framework components. We will be heavily relying on our
previous knowledge gained for Rest Assured, Cucumber as well as Maven. Subsequently, these will form the base
over which we will build our API Automation Framework. I will be referring to them every once in a while and adding
useful links as we need more of them. It's advisable to clear up the basics by going through the tutorials:
Page | 171
1. Rest Assured
2. Cucumber
3. Maven
In our automation framework, we will automate an End to End business flow of a use case. Additionally, it will help
to demonstrate the right examples of framework components and explain their usages. Besides, our understanding
of building the Rest Assured API Automation Framework from scratch will improve as we go about this tutorial.
Many-a-times we are involved in getting ready-made frameworks that are built by Senior Test Architects or Software
Developers. Understanding the underlying principles and design ideas are crucial to develop our skills as software
engineers.
1. Java Setup
2. IDE Setup
3. Maven Setup
We will use Java as our language, for writing our REST API automation framework based on the Rest Assured library.
For this, we will need to install Java on our machines if not previously installed. Likewise, please follow through the
tutorial to install Java as our first prerequisite.
As we will be working with Java, we will need an editor to use for Java. Eclipse, IntelliJ, Net Beans, and several others
are popular IDEs you can choose to work. Furthermore, a tutorial on installing Eclipse on Windows and for Mac users
exists to ease the process. Please pick an IDE you are comfortable working with and get going.
Build tools enable us to create executable applications from the source code. They help to automate and script
everyday activities like downloading dependencies, compiling, running our tests, and deployments. Moreover, we
will use the Maven build tool for our End To End Scenarios. We have created a tutorial explaining the installation of
Maven on Windows. Additionally, please install Maven, if not previously installed as we would need it.
Eclipse operates with workspaces, folders, and spaces where you add your projects. Software Teams use different
approaches for workspaces and project structures but try to follow and stick with the default structure.
In addition to this, to create a new maven project, please follow our article Steps to create a New Maven Project.
Just to make sure that you specify below values to Maven Archetype Parameters:
Page | 172
Note: You can have any names as Group ID and Artifact ID. However, for the ease of this tutorial, it is better to keep
the same naming conventions across the project. Also, it helps in resolving issues while copying pasting the code.
We will add Rest Assured Dependencies to our project through the pom.xml file. To add the required dependencies,
go to Rest Assured Maven Repository. Then, select the latest dependency. Copy-paste it in the project pom.xml file.
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.2.0</version>
<scope>test</scope>
</dependency>
We should add the dependency tag within the dependencies tag, like below.
<dependencies>
<dependency>Project Dependency</dependency>
</dependencies>
Further, we will be using JUnit Dependency. So please add that dependency in the pom.xml.
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
Note: As of Feb'2020, the latest JUnit version is 4.13. Always use the latest Junit version.
The Compiler Plugin compiles the sources of the project. Regardless of the JDK you run Maven with, the default
source setting is 1.5, and the default target setting is 1.5. Additionally, to change the defaults, please set the source
and target as described in Setting the –source and –target of the Java Compiler.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
Page | 173
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
<project xmlns="https://maven.apache.org/POM/4.0.0"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ToolsQA</groupId>
<artifactId>RestAssured_APITests</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.2.0</version>
<scope>test</scope>
</dependency>
</dependencies>
Page | 174
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
Finally, before we begin automation of our tests, the last piece is remaining. It is of creating an authorized user. We
need to create a user that will use our End to End automation tests. We have learned to create a user in our previous
tutorial under the POST Request. The POST Request tutorial explains how a POST Request method sends data to the
server.
@Test
RestAssured.baseURI = "https://bookstore.toolsqa.com";
requestParams.put("UserName", "TOOLSQA-Test");
requestParams.put("Password", "Test@@123");
request.body(requestParams.toJSONString());
Page | 175
Response response = request.post("/Account/v1/User");
Assert.assertEquals(response.getStatusCode(), 201);
// We will need the userID in the response body for our tests, please save it in a local variable
Test Scenario: As an existing authorized user, I retrieve a list of books available for me in the library. I will assign a
book to myself and later on return it.
We will divide the test scenario into below steps for simplicity:
1. Test will start from generating Token for Authorization - First, we have the username and password of a
registered user. Using these credentials, we will generate a token. Additionally, we will send this token into the
Requests instead of the username and password. The reason we follow this practice is to have specific resources
allocated in a time-bound manner. This step involves making a POST Request call in Rest Assured by passing
username and password. Kindly follow this POST Request tutorial to learn about how to send a POST Request.
Note: The below-mentioned User won't work, please create your user for practice.
2. Get List of available books in the library - Secondly, it is a GET Request call. It gets us, the list of available books.
Visit the GET Request tutorial to understand the logic of how we make a GET Request call in Rest-Assured.
3. Add a book from the list to the user - The third is a POST Request call. We will send the user and book details in
the Request.
4. Delete the added book from the list of books - Fourth is a DELETE Request call. We will delete the added book
from the list. The DELETE Request tutorial will help you with it.
5. Confirm if the book removal happens successfully - Last but not least, as a verification step, we will verify if the
book has got removed from the user. Therefore, we will send user details in a GET Request call to get details of the
user.
1. Firstly create a New Package by right click on the src/test/java package and select New >> Package.
Moreover, give your package a name apiTests and click Finish.
2. Secondly, create a New Class file by right click on the src/test/java package and select New >> Class. Give
your test case the correct name in the resulting dialog and click Finish to create the file. Also, to make sure
to check the public static void main, as we will be running the test from the same primary method. I have
named the class as E2E_Tests, as you can see in the code snippet below.
I have written an end to end test encompassing the steps as mentioned above. The example is relatively simple to
follow through. Moreover, it involves the use of GET, POST, and DELETE Requests. It will benefit you if you go
through the Rest Assured Tutorial at this point if you are not following.
package apiTests;
Page | 176
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import io.restassured.RestAssured;
import io.restassured.path.json.JsonPath;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
RestAssured.baseURI = baseUrl;
//Step - 1
request.header("Content-Type", "application/json");
.post("/Account/v1/GenerateToken");
Assert.assertEquals(response.getStatusCode(), 200);
Assert.assertTrue(jsonString.contains("token"));
Page | 177
//This token will be used in later requests
//Step - 2
response = request.get("/BookStore/v1/Books");
Assert.assertEquals(response.getStatusCode(), 200);
jsonString = response.asString();
//This bookId will be used in later requests, to add the book with respective isbn
//Step - 3
//The token we had saved in the variable before from response in Step 1,
//we will be passing in the headers for each of the succeeding request
.header("Content-Type", "application/json");
.post("/BookStore/v1/Books");
//Step - 4
Page | 178
// Delete a book - with Auth
.header("Content-Type", "application/json");
response = request.body("{ \"isbn\": \"" + bookId + "\", \"userId\": \"" + userID + "\"}")
.delete("/BookStore/v1/Book");
Assert.assertEquals(204, response.getStatusCode());
//Step - 5
// Get User
.header("Content-Type", "application/json");
Assert.assertEquals(200, response.getStatusCode());
jsonString = response.asString();
Assert.assertEquals(0, booksOfUser.size());
Note: We added an import statement for JSONpath, import io.restassured.path.json.JsonPath; It will help us to
traverse through the specific parts of the JSON. You can read more in the JSONPath article.
Next step, we need to execute the test. Right-click in the test body and select Run As >> Java Application. The test
will run, and you'll see the results in the Console. Consequently, the program executes successfully without any
error. Just in case you happen to configure the same on IntelliJ IDE, the effect observed will be "Process finished
with exit code 0". Additionally, it is another sign signifying that there were no errors and our tests executed
successfully.
Note: It is not a UI based test. Moreover, there will not be any visual output to observe the test execution.
Conclusively, in the next tutorial, we will Convert our API tests into Cucumber BDD style. It will further our
understanding of the way Cucumber Tests are structured.
We will use the Cucumber BDD Framework to execute our tests. Additionally, it would require us to Convert our
Rest Assured API Tests to the Cucumber BDD Style Test.
Firstly, add the following dependencies to our project to execute our tests in Cucumber:
• cucumber-java
• cucumber-jvm-deps
• cucumber-JUnit
As we are developing the framework in Maven, it would be useful to add the dependencies. Therefore, add the
following dependencies into the project POM XML.
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-jvm-deps</artifactId>
<version>1.0.6</version>
<scope>provided</scope>
</dependency>
Page | 180
Note: As of Feb’2020, the latest cucumber-jvm-deps version is 1.0.6
<dependency>
<groupId>io.cucumber<</groupId>
<artifactId>cucumber-junit</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
<modelVersion>4.0.0</modelVersion>
<groupId>ToolsQA</groupId>
<artifactId>RestAssured_APITests</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
Page | 181
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-jvm-deps</artifactId>
<version>1.0.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
Note: Update the POM by right click on the project root and select Maven >> Update Project. This action will nullify
the dependencies based issues.
Additional note: If you feel comfortable adding the jars in the project library instead of using Maven dependencies,
that's alright as well.
Page | 182
Step 2: Write a test in a Feature File
Secondly, we will highly recommend acquainting yourself with the tutorial on the Feature file. It will help in
understanding the basics of the Cucumber feature file. Consequently, we will begin to convert our test scenario into
the Cucumber Feature file.
In the previous chapter, we broke down the scenario into parts for us to easily convert the scenario into steps. Let's
visit the scenario yet again,
1. First, create a New Package and name it as functionalTests. You can do it by right-clicking on
the src/test/resources and select New >> Package.
Note: It's always recommendable to put all the feature files in the resources folder.
2. Secondly, create a Feature file and name it as End2End_Test.feature by right click on the above created
package and select New >> File.
Page | 183
Note: As you are aware, the keywords used in the test steps are in different colors. Those are the Gherkin keywords.
Eclipse does not understand these. However, if we install the cucumber Eclipse plugin-in, this will be recognized.
Please follow our tutorial to Install Cucumber Eclipse Plugin.
Thirdly, we will create a Cucumber Test Runner to execute our tests. Moreover, we will need a Cucumber Test
Runner based on the JUnit Test Runner for our tests. To understand more about Cucumber Test Runner, please
refer JUnit Test Runner for the tutorial.
1. Firstly, Right-click on the src/test/java and select a New Package by using New >> Package. Name it
as runners.
2. After that, Create a New Java Class file and name it as TestRunner by right click on the above-created
package and select New >> Class.
package runners;
@RunWith(Cucumber.class)
@CucumberOptions(
features = "src/test/resources/functionalTests",
Note: Do not select the public static void main while creating the runner class.
Fourthly, as we move ahead in our next step to convert the test code to Step file, we need to revise our knowledge
on Cucumber Step Definitions.
1. To reduce our efforts in step creation, we will automatically generate the much required Cucumber Steps for
implementation. Consequently, we will execute the TestRunner class for this. Right-click on
Page | 184
the TestRunner file and select Run As >> JUnit Test. Therefore, you would get the below result in the Eclipse
Console.
2. Create a New Package and title it as stepDefinitions by right click on the src/test/java and select New >>
Package.
3. After that, create a New Java Class and name it is as Steps by right click on the above created package and
select New >> Class.
4. Finally, copy all the steps created by Eclipse to this Steps file and start filling up these steps with Selenium
Code. Select all the code from our Selenium Test file created in the End2End_Test. The Steps test file will
look like this:
package stepDefinitions;
import java.util.List;
import java.util.Map;
Page | 185
import org.junit.Assert;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import io.restassured.RestAssured;
import io.restassured.path.json.JsonPath;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
RestAssured.baseURI = BASE_URL;
request.header("Content-Type", "application/json");
.post("/Account/v1/GenerateToken");
Page | 186
token = JsonPath.from(jsonString).get("token");
RestAssured.baseURI = BASE_URL;
response = request.get("/BookStore/v1/Books");
jsonString = response.asString();
bookId = books.get(0).get("isbn");
RestAssured.baseURI = BASE_URL;
.header("Content-Type", "application/json");
.post("/BookStore/v1/Books");
Assert.assertEquals(201, response.getStatusCode());
Page | 187
@When("I remove a book from my reading list")
RestAssured.baseURI = BASE_URL;
.header("Content-Type", "application/json");
response = request.body("{ \"isbn\": \"" + bookId + "\", \"userId\": \"" + USER_ID + "\"}")
.delete("/BookStore/v1/Book");
Assert.assertEquals(204, response.getStatusCode());
RestAssured.baseURI = BASE_URL;
.header("Content-Type", "application/json");
Assert.assertEquals(200, response.getStatusCode());
jsonString = response.asString();
Assert.assertEquals(0, booksOfUser.size());
Note: As compared to our E2E tests created, we have made the following changes:
• Declared the variables as private static final to not allow changes outside the class.
Page | 188
• We have updated method names and not kept the same as auto-generated ones.
5. The TestRunner file must be able to find the steps files. To achieve that, we need to mention the path of the
package. This path has all of our step definitions in CucumberOptions. Additionally, to know more about the
parameters we can add in the @CucumberOptions, please visit our tutorial Cucumber Options.
package runners;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;
@RunWith(Cucumber.class)
@CucumberOptions(
features = "src/test/resources/functionalTests",
glue = {"stepDefinitions"},
monochrome = true,
strict = true
Note: By default, the Junit/Cucumber finds the test code in the src/test/java folder. Hence, this is why we just need to
specify the package name for the cucumber glue.
Run as JUnit
Finally, we are all set to run the first Cucumber test. Right -Click on TestRunner class and Click Run As >> JUnit
Test. Cucumber will execute the script the same way it runs in Selenium WebDriver. Consequently, the result will
appear in the left-hand side project explorer window in the JUnit tab.
Page | 189
We have a Maven Type project, and thus, we can run our tests from the command prompt as well. A simple
command to run tests is an mvn clean test. Moreover, to use this command, we have to change our directory to the
location of our Cucumber project. In the below screenshot first, I went to my project location, and then I used the
Maven as mentioned above command to run the test.
Consequently, we can see the output of the tests below in the command prompt.
To conclude, by now, we have converted our Rest Assured API tests into Cucumber based tests. Subsequently, we
will see how to implement the Java serialization concept in our Framework and enhance it. Moreover, it would be
useful at this stage to go through the Convert JSON to JAVA Object tutorial as a refresher before advancing on the
next framework tutorial.
.post("/Account/v1/GenerateToken");
We are sending the body request in a raw JSON string format. It is cumbersome to maintain and error-prone to send
the request body in this format. Right now, we are dealing with just two parameters. But, there is a possibility that in
actual body requests, we could have to deal with more number of parameters.
Additionally, it is advisable to send the username and password in the request body as an object. To achieve this we
need to convert JSON to JAVA Object. But, the network does not understand Java objects. So, we would need to
serialize the objects into String before sending the request.
We can do this using many serialization-deserialization libraries available. But, Rest Assured has this functionality in-
built. It enables us to directly send objects in Rest Assured requests while the Library takes care of Serialization
internally. If you dive deeper to understand the implementation of RequestSpecification, you will see the below code
snippet which clearly shows how Rest Assured takes care of Serialization.
Page | 190
So we will now understand the process of converting a JSON request into a Java object in the next section.
We are focussing on creating a POJO class for our request object. So, let us learn to create a POJO class out of
a JSON. Let's begin with one simple request example from our Request Body:
In the Request body for this API, we are sending the username and password as the request body.
As seen in the above Swagger bookstore API document, the request JSON body parameters we pass in the request
body is:
"userName": "TOOLSQA-Test",
Page | 191
"password": "Test@@123"
Moreover, you can manually create a POJO class having all listed fields of the JSON body. Also, there are various
utilities available online for free using which we can convert any JSON structure to a Java POJO class.
How to create a Java POJO Class for a JSON Request Body using Online Utility?
Here we will see How to Convert a JSON String into Java Object. So, let's take the help of one of the websites to
help us convert the JSON to a Java POJO class.
• Thirdly, enter the package name and class name in the right-side panel.
• Finally, enter other required selection details as per the image below.
Page | 192
Explanation
Thus, with our inputs of a JSON with username and password as fields, we have created a POJO. Additionally, we will
use this POJO to send into the request body of our API /Account/v1/GenerateToken.
• Token Request
• ISBN
2. Secondly, replace the Request bodies in Step files with POJO class objects.
Page | 193
As shown in the above image from our Swagger bookstore API documentation for the Generate Token API, the
request body is:
"userName": "TOOLSQA-Test",
"password": "Test@@123"
1. Firstly, Right-click on the src/test/java and select New >> Package. After that, create a New Package file and
name it as apiEngine. Further inside, the apiEngine Package creates a new Package with the name as
the model. Moreover, inside this model Package, create a Package with the name requests. We will capture
all the requests classes under this package.
2. Secondly, create a New Class file under it and name it as AuthorizationRequest, by right click on the above-
created Package and select New >> Class.
AuthorizationRequest.class
package apiEngine.model.requests;
this.username = username;
this.password = password;
Code Explanation
The Bookstore URL requires the client to send the username and password as we studied in the API Documentation
tutorial for Authorization Token. We have defined the class AuthorizationRequest for this purpose. We will create an
object of AuthorizationRequest with a constructor with the parameters username and password.
Similarly, we will create classes for Add Books Request, Remove Books Request, and ISBN.
As we saw in the Swagger bookstore API documentation for the Add Books API, the request body is:
"userId": "string",
"collectionOfIsbns": [
Page | 194
{
"isbn": "string"
To create a POJO class of the JSON request body, Right-click on the above-created request Package and select New
>> Class. Additionally, name it as AddBooksRequest.
AddBooksRequest.class
package apiEngine.model.requests;
import java.util.ArrayList;
import java.util.List;
//As of now this is for adding a single book, later we will add another constructor.
this.userId = userId;
collectionOfIsbns.add(isbn);
Code Explanation
The AddBooksRequest class will be responsible for providing us an object that adds a book into the user account.
While we are at it, we would need the userId and the unique identifier of the book, ISBN. Thus,
the userID and isbn pass as a parameter into the AddBooksRequest class object.
Right-click on the above-created request Package. After that, select New >> Class. Name it as ISBN.
package apiEngine.model.requests;
Page | 195
public class ISBN {
this.isbn = isbn;
Code Explanation
We created the ISBN class to use in the AddBooksRequest class for storing a collection of the type ISBN.
As we saw in the Bookstore API for Remove Books Endpoint, the request body is:
"isbn": "string",
"userId": "string"
To create a POJO class of the JSON request body, Right-click on the above-created request Package and select New
>> Class. Additionally, name it as RemoveBookRequest.
package apiEngine.model.requests;
this.userId = userId;
this.isbn = isbn;
Code Explanation
With the help of RemoveBooksRequest class, we will create an object by passing the parameters userId and isbn.
Moreover, the request body uses this object.
Replace the Request Bodies in Step files with POJO class objects
Lets just first start with the first step of the test that is "Given("^I am an authorized user$")"
Page | 196
@Given("^I am an authorized user$")
RestAssured.baseURI = BASE_URL;
request.header("Content-Type", "application/json");
response = request.body(authRequest).post("/Account/v1/GenerateToken");
token = JsonPath.from(jsonString).get("token");
Code Explanation
We have created an object, authRequest of the class AuthorizationRequest. In this object, we are
passing username and password. Additionally, this authRequest object will pass in the body of the request.
In a similar vein, we will make changes for the following Step Definitions to use Java objects that we created using
the POJOs we defined. Internally, the rest assured library will take care of serializing this object into JSON string
before sending the request over the network. Thus, we do not have to worry about serializing the request objects.
Also, note that for the remaining three Step Definitions, we would not be making any changes for now.
package stepDefinitions;
import java.util.List;
import java.util.Map;
import apiEngine.model.requests.AddBooksRequest;
import apiEngine.model.requests.AuthorizationRequest;
import apiEngine.model.requests.ISBN;
import apiEngine.model.requests.RemoveBookRequest;
Page | 197
import org.junit.Assert;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import io.restassured.RestAssured;
import io.restassured.path.json.JsonPath;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
RestAssured.baseURI = BASE_URL;
request.header("Content-Type", "application/json");
response = request.body(credentials).post("/Account/v1/GenerateToken");
token = JsonPath.from(jsonString).get("token");
Page | 198
@Given("^A list of books are available$")
RestAssured.baseURI = BASE_URL;
response = request.get("/BookStore/v1/Books");
jsonString = response.asString();
bookId = books.get(0).get("isbn");
RestAssured.baseURI = BASE_URL;
.header("Content-Type", "application/json");
response = request.body(addBooksRequest).post("/BookStore/v1/Books");
Assert.assertEquals(201, response.getStatusCode());
RestAssured.baseURI = BASE_URL;
Page | 199
RequestSpecification request = RestAssured.given();
.header("Content-Type", "application/json");
response = request.body(removeBookRequest).delete("/BookStore/v1/Book");
Assert.assertEquals(204, response.getStatusCode());
RestAssured.baseURI = BASE_URL;
.header("Content-Type", "application/json");
Assert.assertEquals(200, response.getStatusCode());
jsonString = response.asString();
Assert.assertEquals(0, booksOfUser.size());
Note: We added an import statement for JSONpath, import io.restassured.path.json.JsonPath; It will help us to
traverse through the specific parts of the JSON. Moreover, you can read more in the JSONPath article.
Now, if we try to run our tests, using TestRunner after making all the changes in the Steps file, our tests will fail.
java.lang.IllegalStateException: Cannot serialize object because no JSON serializer found in classpath. Please put
Jackson (Databind), Gson, Johnzon, or Yasson in the classpath.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
Page | 200
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:80)
at
org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrapNoCoerce.callConstructor(Construc
torSite.java:105)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:59)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:237)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:249)
at io.restassured.internal.mapping.ObjectMapping.serialize(ObjectMapping.groovy:160)
at io.restassured.internal.mapping.ObjectMapping$serialize.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
at io.restassured.internal.RequestSpecificationImpl.body(RequestSpecificationImpl.groovy:751)
at stepDefinitions.Steps.iAmAnAuthorizedUser(Steps.java:38
We are missing a key element in the whole show. As explained above in the first section, Rest Assured takes care of
Serialization internally. We also confirmed it in the code snippet. The Rest Assured library depends on the Jackson
(Databind) library, to do this work of Serialization. Since we haven’t yet added this library, we faced the error.
Let us quickly add the dependency in our framework project file pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.2</version>
</dependency>
Note: As of Feb 2019, the latest available dependency for jackson-databind was of version 2.10.2. Please use the
latest dependencies when you build your framework.
<modelVersion>4.0.0</modelVersion>
<groupId>ToolsQA</groupId>
<artifactId>APITestingFramework</artifactId>
Page | 201
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-jvm-deps</artifactId>
<version>1.0.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
Page | 202
<version>2.10.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
Now we are all set to run the updated Cucumber test. Right -Click on TestRunner class, and after that, click Run
As >> JUnit Test. Consequently, the result will display in the JUnit tab of the console.
To run the tests as a Cucumber Feature, right-click on the End2End_Test.feature file. After that, select the Run
As>>Cucumber Feature.
Page | 203
As you can see in the screenshot attached above, our tests have passed with the changes. We have Convert JSON to
JAVA Object using Serialization in this chapter. Please try to implement it in your framework, as explained above.
Below is the screenshot of the current project explorer.
Page | 204
Subsequently, we will visit the Convert JSON Response Body to POJO in our next chapter.
Additionally, to learn more about the deserialization of JSON response, we will recommend you to go through
the Deserialize JSON Response.
We will follow the below steps to achieve the deserialization of our responses in the framework. We followed them
in the previous chapter of Convert JSON Request Body to Java Object as well.
• Book
Page | 205
• Books
• Token
• User Account
2. Replace the Response bodies in Step files with POJO class objects
Firstly, we need to convert the JSON Response into a POJO class for our response object. So, let us learn to create
a POJO class out of a JSON Response. Under deserialization, we will study our JSON body parameters and create
a POJO class of it. Let's begin with a straightforward request example for Get A Book request:
As a part of this request, we are sending the ISBN parameter to get details of a specific book.
Consequently, the response body from the Swagger Bookstore API, as highlighted in the above image is:
Page | 206
{
"books": [
"isbn": "9781449325862",
"published": "2013-08-02T00:00:00",
"pages": 234,
"description": "This pocket guide is the perfect on-the-job companion to Git, the distributed version control
system. It provides a compact, readable introduction to Git for new users, as well as a reference to common
commands and procedures for those of you with Git experience.",
"website": "https://chimera.labs.oreilly.com/books/1230000000561/index.html"
As a part of the next step, we will create a POJO class for our response object. Additionally, you may use the
same online utility, as we discussed in the previous chapter, to convert the response to a POJO class.
1. Firstly, Right-click on the model Package under the apiEngine package. After that, select New>>Class. Name it as
Book. Moreover, we will capture the book response under this class.
Book.class
package apiEngine.model;
Page | 207
Code Explanation
This Book class will contain all the fields we got in the response, such as title, isbn, author, no.of pages, etc.
The response body from the Bookstore API, as highlighted in the below image is:
"userID": "9b5f49ab-eea9-45f4-9d66-bcf56a531b85",
"userName": "TOOLSQA-Test",
"books": [
"isbn": "9781449325862",
Page | 208
"title": "Git Pocket Guide",
"published": "2013-08-02T00:00:00",
"pages": 234,
"description": "This pocket guide is the perfect on-the-job companion to Git, the distributed version control
system. It provides a compact, readable introduction to Git for new users, as well as a reference to common
commands and procedures for those of you with Git experience.",
"website": "https://chimera.labs.oreilly.com/books/1230000000561/index.html"
Note: As a part of the response body, we got the book details of the book we added for the user as well as other user
details such as userName and userID.
1. Firstly, in this model Package, Right-click on the model and select New >> Package. Name it
as responses. Additionally, we will capture all the response classes under this package.
2. Secondly, Right-click on the above-created responses Package and select New >> Class. Name it as Books.
Books.class
package apiEngine.model.responses;
import java.util.List;
import apiEngine.model.Book;
Code Explanation We created the class Books to hold a list of the type Book which we receive in the JSON response
in GET Books Request.
We have understood the process of creating a POJO class by now, as shown in the above examples. So, in the next
APIs, I will directly add the POJO of respective API's. Consequently, the response body for Generate Token API from
our Bookstore API is:
"token": "string",
Page | 209
"expires": "2020-03-14T13:42:15.716Z",
"status": "string",
"result": "string"
To create a POJO class of it, Right-click on the above-created responses Package and select New >> Class. After that,
name it as Token.
package apiEngine.model.responses;
Code Explanation
We created the class Token that will contain all the fields we got in the response field, namely, token, expiry, status,
and a result which we receive in the JSON response of GenerateToken.
"userID": "9b5f49ab-eea9-45f4-9d66-bcf56a531b85",
"userName": "TOOLSQA-Test",
"books": []
To create a POJO class of the response body, Right-click on the above-created responses Package. After that,
select New >> Class. Name it as UserAccount.
package apiEngine.model.responses;
import java.util.List;
import apiEngine.model.Book;
Code Explanation
We created the class UserAccount to hold the information associated with the user account, such as books
associated with the user, the userID, and userName.
As our next step of project implementation, we shall modify our Steps class.
Replace the Response bodies in Step files with POJO class objects
Now it is the time to make use of the POJO classes created above in the test code. Let's have a look at the one of the
old cucumber step below in the Step Definition:
RestAssured.baseURI = BASE_URL;
request.header("Content-Type", "application/json");
response = request.body(credentials).post("/Account/v1/GenerateToken");
token = JsonPath.from(jsonString).get("token");
we update it likewise:
RestAssured.baseURI = BASE_URL;
request.header("Content-Type", "application/json");
response = request.body(authRequest).post("/Account/v1/GenerateToken");
Page | 211
// Deserializing the Response body into tokenResponse
tokenResponse = response.getBody().as(Token.class);
Note The import statement: import io.restassured.path.json.JsonPath; is no longer needed as we have deserialized
our response to Token class.
Code Explanation: We deserialized the response body into the Token class in this step above. This response body
gets saved in the "tokenResponse" variable. The saved variable will be used further in a request along with the
token.
package stepDefinitions;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import apiEngine.model.Book;
import apiEngine.model.requests.AddBooksRequest;
import apiEngine.model.requests.AuthorizationRequest;
import apiEngine.model.requests.ISBN;
import apiEngine.model.requests.RemoveBookRequest;
import apiEngine.model.response.Books;
import apiEngine.model.response.Token;
import apiEngine.model.response.UserAccount;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import io.restassured.RestAssured;
import io.restassured.path.json.JsonPath;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
RestAssured.baseURI = BASE_URL;
request.header("Content-Type", "application/json");
response = request.body(credentials).post("/Account/v1/GenerateToken");
tokenResponse = response.getBody().as(Token.class);
RestAssured.baseURI = BASE_URL;
response = request.get("/BookStore/v1/Books");
book = books.books.get(0);
RestAssured.baseURI = BASE_URL;
.header("Content-Type", "application/json");
response = request.body(addBooksRequest).post("/BookStore/v1/Books");
Assert.assertEquals(201, response.getStatusCode());
Assert.assertEquals(USER_ID, userAccount.userID);
Assert.assertEquals(book.isbn, userAccount.books.get(0).isbn);
RestAssured.baseURI = BASE_URL;
.header("Content-Type", "application/json");
response = request.body(removeBookRequest).delete("/BookStore/v1/Book");
}
Page | 214
@Then("The book is removed")
Assert.assertEquals(204, response.getStatusCode());
RestAssured.baseURI = BASE_URL;
.header("Content-Type", "application/json");
Assert.assertEquals(200, response.getStatusCode());
Assert.assertEquals(0, userAccount.books.size());
We are all set now to run the updated Cucumber test. First, Right -Click on TestRunner class and Click Run
As >> JUnit Test. Cucumber runs the script in the same way as Selenium WebDriver. Consequently, the result will
display in the JUnit tab of the console.
To run the tests as a Cucumber Feature, right-click on the End2End_Test.feature file. After that, select the Run
As>>Cucumber Feature.
Page | 215
Our tests passed with the changes we made for the conversion of the JSON Response Body to Java Object. Please try
to implement it in your framework, as explained above, and share your valuable feedback.
After creating the above POJO classes, the project folder structure will look likewise:
Subsequently, we will attempt the separation of Test Layer with API Services in our next chapter.
Page | 216
Separation of Test Layer with API Services
We learned to convert JSON Request Body as well as JSON Response Body to Java Object in the previous chapters.
We used Serialization and Deserialization concepts to achieve this. It led to our tests becoming more maintainable
and less error-prone. Now in this chapter, we will work on the Separation of Test Layer with API Services and take a
step further to make our tests cleaner and maintainable.
If you look at the Steps class, which is our test layer, you would see that we have a lot of logic that isn't actually
related to testing. It concerns communicating with the server with a given test request and getting a response. Refer
to the screenshot below:
In actual projects, we have a large number of APIs and tests implemented. They all contain the same logic of
communicating with the server in every test, like:
• Adding headers
This leads to a lot of code duplication in every test file. Additionally, if tomorrow there are some changes required in
a particular endpoint, we will need to make changes in several places. It is not advisable because it makes our
framework less maintainable.
Additionally, the test layer needs to focus only on the test data (parameters) sent in the request and receive
responses from the APIs. It should not be focused on the heavy logic of the internals of API implemented. So, as
software testers, we are only interested in the request and response obtained for these requests. Moreover, the test
data sent in the request generally pass from the feature file in the Cucumber framework. This test data can be
parameters to form a request body, request header or request resources.
As we have seen in our first chapter Understanding API Documentation, endpoints indicate ways to access
resources from the server. Thus, we will essentially combine all the logic of endpoints from our Steps file and move it
to a common class. The class will contain methods that take the required request parameters and send back a
Page | 217
response received from the server. The endpoints should always get the request body from the test layer. In this
article, we are going to cover:-
We abstract the logic of communication with the server into a separate class. It will make our Steps class cleaner.
Subsequently, as we progress to write more steps into Step-Definition files in the framework, for different scenarios,
we can reuse this logic of communicating with the server.
Consider the example to generate a token request of our Book Store API: /Account/v1/GenerateToken
For writing tests to test the generate token, our tests should focus the response obtained for the request body
passed. In addition to this, they should not focus on internal implementation for the API. In a project with a large
number of APIs, it is better to separate the Endpoints from Steps file.
Moreover, if we send correct credentials, we get a success response as a result. Refer below screenshot:
Page | 218
But, if we send invalid credentials, we will get an error response.
Thus, as testers, the focus is on the parameters sent in the body of the request and response we get. It is as same as
what we are doing at the Book Store API in Swagger Tool above. We do not have a clue how swagger is making use
of HTTP and how it is communicating with the server. The same way the test layer should be agnostic, the fact of
how the service layer is handling the request. Additionally, a test layer should only focus on parameters passed to
the request, whether it is query parameter, header parameters, or a body parameter, etc.
Let's see how to separate the Service layer from the Test layer.
Now we are going to create API Services, which will be consumed by the test layer, and this way, the test layer will
be clean and efficiently focus only on test parameters.
package apiEngine;
We are moving all our endpoints to the Endpoints class. It is rational to move the BASE URL as well to the Endpoints
class from Steps file. Moreover, it will help us to refer to the BASE URL when sending requests to our endpoints.
package apiEngine;
Firstly, we will extract the way to authenticate the user from Steps into Endpoints class. Additionally, we shall pass
the object of *AuthorizationRequest *to the method.
RestAssured.baseURI = BASE_URL;
request.header("Content-Type", "application/json");
return response;
Code Explanation:
As you can see, we have created a method authenticateUser. In this method, we pass user credentials
through AuthorizationRequest object, authRequest in the Request. Moreover, we are passing the BASE_URL and the
headers as part of the request as well.
• getBooks()
• addBook()
• removeBook()
• getUserAccount()
Endpoints.java class
package apiEngine;
Page | 220
import apiEngine.model.requests.AddBooksRequest;
import apiEngine.model.requests.AuthorizationRequest;
import apiEngine.model.requests.RemoveBookRequest;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
RestAssured.baseURI = BASE_URL;
request.header("Content-Type", "application/json");
return response;
RestAssured.baseURI = BASE_URL;
request.header("Content-Type", "application/json");
return response;
RestAssured.baseURI = BASE_URL;
return response;
RestAssured.baseURI = BASE_URL;
.header("Content-Type", "application/json");
return response;
RestAssured.baseURI = BASE_URL;
.header("Content-Type", "application/json");
return response;
We now move to our next step. In the next step, we will replace the endpoints in the Steps file with our newly
created methods.
Page | 222
We have abstracted the logic of communication with the server into an Endpoint class. It will now help us make our
Steps class cleaner as we progress into replacing the endpoints with the associated methods. In addition to this, we
will be reusing this logic of communicating with the server.
Thus, the first part of the Steps class, with changes in the declared variables will be:
is updated as:
response = EndPoints.authenticateUser(authRequest);
tokenResponse = response.getBody().as(Token.class);
We will likewise modify the rest of our step definitions. Moreover, we put all these changes for the Step Definitions
together into the Steps file.
package stepDefinitions;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import apiEngine.Endpoints;
import apiEngine.model.Book;
import apiEngine.model.requests.AddBooksRequest;
import apiEngine.model.requests.AuthorizationRequest;
import apiEngine.model.requests.ISBN;
import apiEngine.model.requests.RemoveBookRequest;
Page | 223
import apiEngine.model.response.Books;
import apiEngine.model.response.Token;
import apiEngine.model.response.UserAccount;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import io.restassured.response.Response;
response = Endpoints.authenticateUser(authRequest);
tokenResponse = response.getBody().as(Token.class);
response = Endpoints.getBooks();
book = books.books.get(0);
Assert.assertEquals(201, response.getStatusCode());
Assert.assertEquals(USER_ID, userAccount.userID);
Assert.assertEquals(book.isbn, userAccount.books.get(0).isbn);
Assert.assertEquals(204, response.getStatusCode());
Assert.assertEquals(200, response.getStatusCode());
Assert.assertEquals(0, userAccount.books.size());
We are all set now to run the updated Cucumber test. Firstly, Right -Click on TestRunner class and Click Run
As >> JUnit Test. Cucumber will run the script in the same fashion as it runs in Selenium WebDriver. Finally, the
result will display in the left-hand side project explorer window in the JUnit tab.
Page | 225
To run the tests as a Cucumber Feature, right-click on the End2End_Test.feature file. After that, select the Run
As>>Cucumber Feature.
Moreover, our updated project folder structure of the framework will look likewise:
In the next chapter, we will introduce the Implementation of Routes in Endpoints in our API automation framework.
That would help us to make the framework maintainable and we won't have to make changes everywhere when the
route changes except for Routes class. Additionally, please implement the Endpoints class as discussed above, and
share your valuable feedback with us.
In addition to the above, the RESTful routes can be akin to a traditional pattern followed when structuring different
routes. It interacts with the server each time an HTTP request happens.
http://bookstore.toolsqa.com/BookStore/v1/Books:
BasePath: http://bookstore.toolsqa.com/
Route: /BookStore/v1/Books
Endpoint: There can be multiple tasks we can perform on this route. For example:
Let us add the Routes we discussed above in the first section to our Route class. We will keep all the routes at a
single place, and wherever the routes are required, we will use it from this class.
Moreover, the advantage it gives is that suppose any of the route changes. We won't have to make changes
everywhere. In other words, it's just at a single place in the Routes class.
1. Firstly, to create a Route class, Right-click on the apiEngine Package and select New >>Class. Name it
as Route.
package apiEngine;
Page | 227
private static final String BOOKSTORE = "/BookStore";
We will modify the methods in the endpoints class. Additionally, we will pass the routes from the Routes class
instead of writing them to a specific route in the method itself.
For Example:
RestAssured.baseURI = BASE_URL;
request.header("Content-Type", "application/json");
//The hardcoded route "/Account/vi/GenerateToken" will be modified to take the route from the Route class
return response;
to
RestAssured.baseURI = BASE_URL;
Page | 228
RequestSpecification request = RestAssured.given();
request.header("Content-Type", "application/json");
return response;
Explanation:
In this method, the route for generating token is now taken from the Route class instead of passing the
route "/Account/v1/GenerateToken".
1. getBooks()
2. addBook()
3. removeBook()
4. getUserAccount()
package apiEngine;
import apiEngine.model.requests.AddBooksRequest;
import apiEngine.model.requests.AuthorizationRequest;
import apiEngine.model.requests.RemoveBookRequest;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
RestAssured.baseURI = BASE_URL;
request.header("Content-Type", "application/json");
Page | 229
return response;
RestAssured.baseURI = BASE_URL;
request.header("Content-Type", "application/json");
return response;
RestAssured.baseURI = BASE_URL;
.header("Content-Type", "application/json");
return response;
RestAssured.baseURI = BASE_URL;
.header("Content-Type", "application/json");
return response;
Page | 230
public static Response getUserAccount(String userId, String token) {
RestAssured.baseURI = BASE_URL;
.header("Content-Type", "application/json");
return response;
We are all set now to run the updated Cucumber test. First, Right -Click on the TestRunner class. Secondly, Click Run
As >> JUnit Test. Finally, the result will display in the JUnit tab of the console.
To run the tests as a Cucumber Feature, right-click on the End2End_Test.feature file. After that, select the Run
As>>Cucumber Feature.
Page | 231
Our tests passed with the changes we made for the Rest Routes implementation in our framework. Our updated
project folder structure of the framework will look likewise:
Subsequently, in the next chapter, we will implement generics in our framework to handle response objects of
various data types. Meanwhile, please try and apply the above changes in your framework, as explained.
Subsequently, in this chapter, we are going to implement the Generics concept in our framework. We are dealing
with the response objects of various data types such as Token, Books, and User Account. Moreover, one can build
these response objects fail-safe by using generics. Generics adds a layer of abstraction. In addition to that, they add a
way to specify types for classes and methods. You can read more about the Generics concept in this Generics
tutorial. In this article, we are going to cover:-
• Implementation of Generics
Consider an example of returning a Book object from Endpoint method like below:
return response.getBody().as(Books.class);
If we would get a failed response, our code will fail in the above method implementation.
Page | 232
int code = response.getStatusCode();
if( code == 200 || code == 201 || code == 202 || code == 203 || code == 204 || code == 205) {
return response.getBody().as(Book.Class());
we would not be able to test negative tests by sending a wrong body and expecting a 204. We would likely be stuck
in such a case.
Thus we need a class, which will return the Response Body as well as status and in case of failure return exception or
error message.
Now, the response received from the server can be of several data types. Hence, we need an interface capable of
handling different response objects. To provide this parameterized value to a parameterized type, we implement
this as a Generic Interface. This interface will contain all the methods we need when we operate on
a REST Response.
Implementation of Generics
Firstly, right-click on the apiEngine package and select New >> Interface. Name it as IRestResponse.
IRestResponse.java
package apiEngine;
import io.restassured.response.Response;
public T getBody();
Page | 233
public Exception getException();
Explanation:
We created a generic interface of type <T>. Thus, we can use this interface to hold responses of different types. For
example, IRestResponse<Books> will hold the response of type Books. Likewise, it will be for
IRestResponse<UserAccount> and IRestResponse<Token>.
Note: As explained above, we need this interface to return the Body as well as status, and in case of failure return
exception or error message. Therefore, that's why we have those attributes in the interface.
We defined the methods we need to operate on the REST response. We need to apply these methods next in our
Rest Response class.
Right-click on the apiEngine package and select New >> Class. Name it as RestResponse.
package apiEngine;
import io.restassured.response.Response;
private T data;
private Exception e;
this.response = response;
try{
this.data = t.newInstance();
return response.getBody().asString();
Page | 234
public int getStatusCode() {
return response.getStatusCode();
if( code == 200 || code == 201 || code == 202 || code == 203 || code == 204 || code == 205) return
true;
return false;
return response.getStatusLine();
return response;
public T getBody() {
try {
}catch (Exception e) {
this.e=e;
return data;
return e;
Page | 235
Explanation:
We implemented the methods to return us relevant details of REST responses as needed for testing.
• isSuccessful(): Will validate if the sending request was successful. It validates the response status code
received against the numerous HTTP status codes denoting that request was successfully processed
• getResponse().getBody().asString(): We will need the response body content in String format at times. This
method implementation takes care of it.
• getException(): In case our response body is not deserialized successfully, we will get an exception. e will
contain this exception, which we get using this method.
Our methods for Endpoints class will change. They will return responses of the type RestResponse<Books>,
RestResponse<Token> and RestResponse<UserAccount> for the respective methods.
RestAssured.baseURI = BASE_URL;
request.header("Content-Type", "application/json");
return response;
to
RestAssured.baseURI = BASE_URL;
request.header("Content-Type", "application/json");
Explanation:
In this method, we have wrapped the Rest Assured Response into our RestResponse class of the type Token, where
we have deserialized the responses.
1. getBooks()
2. addBook()
Page | 236
3. removeBook()
4. getUserAccount()
package apiEngine;
import apiEngine.model.requests.AddBooksRequest;
import apiEngine.model.requests.AuthorizationRequest;
import apiEngine.model.requests.RemoveBookRequest;
import apiEngine.model.responses.Books;
import apiEngine.model.responses.Token;
import apiEngine.model.responses.UserAccount;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
RestAssured.baseURI = BASE_URL;
request.header("Content-Type", "application/json");
RestAssured.baseURI = BASE_URL;
request.header("Content-Type", "application/json");
RestAssured.baseURI = BASE_URL;
.header("Content-Type", "application/json");
RestAssured.baseURI = BASE_URL;
.header("Content-Type", "application/json");
return request.body(removeBookRequest).delete(Route.book());
RestAssured.baseURI = BASE_URL;
.header("Content-Type", "application/json");
We will modify the step definitions to call the methods listed in the endpoints class.
Moreover, you will directly obtain the response in the step definition class. As already explained, the logic of
communication with the server and converting it into the response class moves out. Thus, our step definition
consists of only the testing layer which we are interested in and not the internal workings of the API.
package stepDefinitions;
import apiEngine.EndPoints;
import apiEngine.IRestResponse;
import apiEngine.model.*;
import apiEngine.model.requests.*;
import apiEngine.model.responses.*;
import org.junit.Assert;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import io.restassured.response.Response;
Page | 239
AuthorizationRequest authRequest = new AuthorizationRequest("TOOLSQA-Test", "Test@@123");
tokenResponse = EndPoints.authenticateUser(authRequest).getBody();
book = booksResponse.getBody().books.get(0);
Assert.assertTrue(userAccountResponse.isSuccessful());
Assert.assertEquals(201, userAccountResponse.getStatusCode());
Assert.assertEquals(USER_ID, userAccountResponse.getBody().userID);
Assert.assertEquals(book.isbn, userAccountResponse.getBody().books.get(0).isbn);
Assert.assertEquals(200, userAccountResponse.getStatusCode());
Assert.assertEquals(0, userAccountResponse.getBody().books.size());
We are all set now to run the updated Cucumber test. Right -Click on TestRunner class and Click Run As >> JUnit
Test. Consequently, you will see the result in the left-hand side project explorer window in the JUnit tab.
To run the tests as a Cucumber Feature, right-click on the End2End_Test.feature file. After that, select the Run
As>>Cucumber Feature.
Our updated project folder structure of the framework will look likewise:
Page | 241
Our tests passed with the changes we made for the Generics implementation in our framework. We will
be Refactoring for Request Headers so that we can make use of a single request object in our next chapter.
Moreover, it will avoid the complexity of adding the auth header repeatedly for each request.
Meanwhile, please try to implement the above changes in your framework, as explained above.
By converting the EndPoint class into an Instance class, it will help us to make use of a Single Request Object. It will
save us the trouble of adding the request header each time we pass the request. Here are the topics which we are
going to cover in this article:-
Page | 242
We are sending this highlighted piece of code - the BASE_URL, the headers in every method, as we call our methods
in the Step Definitions. It leads to us creating the RequestSpecification object again and again when it is the same for
every step. It would be simpler if we created this once for all the steps.
If one uses the static methods, it causes random failures in the tests as they turn flaky if the tests run in parallel in
the future course. Every thread tries to access the available static resource. During this, the thread could come in a
situation where another thread is in a position to access the same static resources. Thus, to avoid the test failures
during parallel execution.
To achieve this, we will need to initialize the RequestSpecification object in the constructor. Therefore now we will
need to make all these methods in Endpoints.java class as non-static.
But what we would achieve from this for the framework? Once the authentication is set in the
RequestSpecification object, it is good for all the subsequent requests. It is not required to set it again during the
next request.
To refactor the existing code to create just a single request object, we follow these steps:
package apiEngine;
Page | 243
import org.apache.http.HttpStatus;
import apiEngine.model.requests.AddBooksRequest;
import apiEngine.model.requests.AuthorizationRequest;
import apiEngine.model.requests.RemoveBookRequest;
import apiEngine.model.responses.Books;
import apiEngine.model.responses.Token;
import apiEngine.model.responses.UserAccount;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
RestAssured.baseURI = baseUrl;
request = RestAssured.given();
request.header("Content-Type", "application/json");
if (response.statusCode() != HttpStatus.SC_OK)
throw new RuntimeException("Authentication Failed. Content of failed Response: " + response.toString() + " ,
Status Code : " + response.statusCode());
Page | 244
Response response = request.get(Route.books());
return request.body(removeBookRequest).delete(Route.book());
Code Explanation:
As you can see in the above code, we have created a constructor which takes care of initializing
the RequestSpecification object with baseURL and Request Headers in the constructor when the Endpoints class
initializes in the Steps file.
We also need token to be passed as well in request Header. For that in the method authenticateUser() when we
get tokenResponse, we set it in the same instance of request. This header will then be available when we make
subsequent calls to the server. Since authenticating the user will always be the first step, we will not need to add the
token in the header for every request we make after that.
Our Steps file too would change as per the Endpoints.java class
package stepDefinitions;
import apiEngine.EndPoints;
import apiEngine.IRestResponse;
import apiEngine.model.*;
import apiEngine.model.requests.*;
Page | 245
import apiEngine.model.responses.*;
import org.junit.Assert;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import io.restassured.response.Response;
endPoints.authenticateUser(authRequest);
book = booksResponse.getBody().books.get(0);
Assert.assertTrue(userAccountResponse.isSuccessful());
Assert.assertEquals(201, userAccountResponse.getStatusCode());
Assert.assertEquals(USER_ID, userAccountResponse.getBody().userID);
Assert.assertEquals(book.isbn, userAccountResponse.getBody().books.get(0).isbn);
response = endPoints.removeBook(removeBookRequest);
Assert.assertEquals(204, response.getStatusCode());
userAccountResponse = endPoints.getUserAccount(USER_ID);
Assert.assertEquals(200, userAccountResponse.getStatusCode());
Assert.assertEquals(0, userAccountResponse.getBody().books.size());
Code Explanation:
Page | 247
We have initialized an Endpoints class object-endpoints and passed the baseURL in the
step iAmAnAuthorizedUser() by invoking a constructor of Endpoints class. Also, this same endpoint object is being
used by all the step definitions instead of calling static Endpoint methods.
We are all set now to run the updated Cucumber test. Subsequently, we will Right-Click on the TestRunner class.
After that, we will Click Run As >> JUnit Test. Consequently, the result will appear in the left-hand side project
explorer window in the JUnit tab.
To run the tests as a Cucumber Feature, right-click on the End2End_Test.feature file. Select the Run As>>Cucumber
Feature.
Our updated project folder structure of the framework will look likewise:
Page | 248
Our tests passed with the changes we made for the Refactoring of the Request Headers in our framework. We
will learn to share Test Context between our Step Definitions so that we can have the step definition file uncluttered
and share the Test Context with all the Step Definition files. It will avoid the complexity of adding the auth header
repeatedly for each request.
Need for Sharing the Test Context between Cucumber Step Definitions
In real-life projects, the expectation is we build a scalable automation framework. Moreover, automation coverage
increases as we add multiple scenarios. If a single step definition file contains all the step definitions, it clutters the
step definition file. Additionally, it becomes non-maintainable. It is thus, imperative to refactor the step definitions
separated under different classes.
In any scenario of a feature file in Cucumber, a series of steps get executed one after one. Every step of the scenario
may possess a state which could prove useful to another step in the same scenario. Thus, the steps depend on the
previously executed steps. Moreover, for this reason, sharing the state among the steps is needed.
In our framework, we have just one scenario for illustration purposes. But, it will grow over a while as we add
numerous scenarios. Additionally, to keep the step definition file uncluttered and share the Test Context with all
the Step Definition files, we will resort to the dependency injection Container PicoContainer. We have implemented
this before in our former Cucumber tutorial with Selenium on sharing Test Context with Cucumber Step Definitions.
As a next step, we will learn the way to implement the Test Context sharing between our Step Definitions in our API
Rest Assured Automation Framework.
How to Share the Test Context between Cucumber Steps using PicoContainer
We will follow the same steps as sharing Test Context with Cucumber Step Definitions to share the data state across
steps:
2. Secondly, create a Test Context class to hold all the objects state.
Add the maven dependency of dependency injection-PicoContainer into our project pom.xml. Additionally, you can
find more details about the version etc. at [Maven Repository - Cucumber PicoContainer]
(https://mvnrepository.com/artifact/io.cucumber/cucumber-picocontainer).
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
Page | 249
<version>5.5.0</version>
<scope>test</scope>
</dependency>
Create a Test Context class which will hold all the objects state
The Text Context class shall encompass all information your Steps files are using. In our framework, we are likewise
using the information from the Endpoints class in the Steps file. So simply, we need to add an object of Endpoints
class into this Test Context class.
1. Firstly, Right-click on the src/test/java and select New >> Package. Moreover, name it as a cucumber. All
the Cucumber Helper classes will be in the same package hereon.
2. Secondly, Right-click on the above-created package and select New >> Class. Name it as TestContext.
TestContext.java
package cucumber;
import apiEngine.EndPoints;
public TestContext() {
return endPoints;
Consequently, we kept the initialization of Endpoints in the constructor and created getEndPoints() for the object.
We can logically divide our endpoints into Account Steps and Book Steps. Some of the necessary steps would include
in the BaseStep.
Create three New Classes in the stepDefinitions package with the following names:
• AccountSteps
Page | 250
• BooksSteps
• BaseStep
Note: You may replace the Steps file with BaseSteps during clean up by moving the required step definitions to
associated classes. Alternatively, you can create a BaseStep class, and once we completed this tutorial, then delete
the Steps file as we no longer would be using it.
We divided the Step Definitions to different Step classes. These classes commonly share the Endpoints class amongst
themselves. Additionally, in real-life projects, we may have such multiple classes that have an extensive requirement
for every Step class. Moreover, to create objects for all standard classes using a new operator, again and again, is not
advisable.
If we add a constructor to our Steps class file and pass TestContext as a Parameter to the constructor, it would solve
all the problems. In the TestContext object, we got everything required for the test.
package stepDefinitions;
import apiEngine.model.requests.*;
import cucumber.TestContext;
import cucumber.api.java.en.Given;
super(testContext);
getEndPoints().authenticateUser(authRequest);
package stepDefinitions;
import apiEngine.IRestResponse;
Page | 251
import apiEngine.model.Book;
import apiEngine.model.requests.AddBooksRequest;
import apiEngine.model.requests.ISBN;
import apiEngine.model.requests.RemoveBookRequest;
import apiEngine.model.responses.Books;
import apiEngine.model.responses.UserAccount;
import cucumber.TestContext;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import io.restassured.response.Response;
import org.junit.Assert;
super(testContext);
book = booksResponse.getBody().books.get(0);
Assert.assertTrue(userAccountResponse.isSuccessful());
Assert.assertEquals(201, userAccountResponse.getStatusCode());
Assert.assertEquals(USER_ID, userAccountResponse.getBody().userID);
Assert.assertEquals(book.isbn, userAccountResponse.getBody().books.get(0).isbn);
response = getEndPoints().removeBook(removeBookRequest);
Assert.assertEquals(204, response.getStatusCode());
userAccountResponse = getEndPoints().getUserAccount(USER_ID);
Assert.assertEquals(200, userAccountResponse.getStatusCode());
Assert.assertEquals(0, userAccountResponse.getBody().books.size());
package stepDefinitions;
import apiEngine.EndPoints;
import cucumber.TestContext;
Page | 253
public class BaseStep {
endPoints = testContext.getEndPoints();
return endPoints;
We are all set now to run the updated Cucumber test. First, Right -Click on TestRunner class and Click Run
As >> JUnit Test. Cucumber runs the script in the same way as Selenium WebDriver. Consequently, the result will
display in the JUnit tab of the console.
To run the tests as a Cucumber Feature, right-click on the End2End_Test.feature file. After that, select the Run
As>>Cucumber Feature.
Page | 254
The tests passed successfully with the changes we made for sharing the Test Context with Cucumber Step
Definitions in our framework. Please try to implement the above changes in your framework, as explained above.
Our updated project folder structure of the framework will look likewise:
In the next chapter, we will introduce the concept of usage of Scenario Context in Framework to share the test data
information specifically. Additionally, we will further segregate our steps into the Verification Steps from the Step
classes.
Scenario Context class holds the test data information explicitly. It helps you store values in a key-value pair
between the steps. Moreover, it helps in organizing step definitions better rather than using private variables in step
definition classes. We have implemented this before in our previous Cucumber tutorial on sharing data between
steps in Cucumber using Scenario Context.
As a next step, we are going to implement the Scenario Context in cucumber for sharing data between our Step
Definitions in our API Rest Assured Automation Framework.
In the end-to-end tests, you're interested in verifying the response for the requests sent. Let’s say you wish to check
the subsequent actions within the tests:
Page | 255
• Addition of Book
• Removal of Book
In that case, we want to store the book details in Scenario Context object while adding the book to the user account.
Likewise, in our next verification step, we remove the book from the user account. Moreover, we retrieve from
the ScenarioContext, book details of the added book, and validate its removal from the user account.
We will follow the identical steps as sharing Scenario Context with Cucumber Step Definitions to share the test data
information state across steps:
2. Secondly, save the test information state within the Scenario Context.
It is a clean code practice to create enums for all the fixed set of values in the project.
1. Firstly, Right-click on the src/test/java and select New >> Package. Moreover, name it as enums. We will
keep all the project enums in this package.
2. Secondly, Right-click on the enums package and select New >> Enum. Name it as Context. Moreover, we will
add our enum in it.
Context.java
package enums;
BOOK,
USER_ID,
USER_ACCOUNT_RESPONSE,
BOOK_REMOVE_RESPONSE;
3. After that, Right-click on the cucumber package and select New >> Class. Name it as ScenarioContext.
package cucumber;
import enums.Context;
import java.util.HashMap;
import java.util.Map;
Page | 256
private Map<String, Object> scenarioContext;
public ScenarioContext(){
scenarioContext.put(key.toString(), value);
return scenarioContext.get(key.toString());
return scenarioContext.containsKey(key.toString());
Code Explanation:
• scenarioContext: It's a HashMap object storing the information in the Key-Value pair. The key type is String.
Moreover, theValue can be of any Object Type.
• setContext(): This method takes two parameters, key as Context and value as an object. Key is nothing but
a Context enum.
• getContext(): This method takes a key as a parameter to returns the object matching the key.
• isContains(): This method checks in the complete Map if the respective key exists or not.
4. Fourthly, include ScenarioContext in TextContext. It will ensure that ScenarioContext is shared across all the
Cucumber Steps using the Pico-Container library. We added in our previous chapter. Moreover, add
a getter method as getScenarioContext() to get the scenarioContext object.
TestContext.java
package cucumber;
import apiEngine.EndPoints;
import enums.Context;
Page | 257
public class TestContext {
public TestContext() {
scenarioContext.setContext(Context.USER_ID, USER_ID);
return endPoints;
return scenarioContext;
package stepDefinitions;
import apiEngine.EndPoints;
import cucumber.ScenarioContext;
import cucumber.TestContext;
endPoints = testContext.getEndPoints();
scenarioContext = testContext.getScenarioContext();
return endPoints;
return scenarioContext;
In this step, we save the responses of our requests to ScenarioContext object. To begin with, we will add the book to
the reading list of the user and save our response. Subsequently, the responses will then validate in our assertions as
a part of the verification steps.
In the below steps of the BooksSteps.java class, we are saving responses to scenario context objects.
BooksSteps.java
package stepDefinitions;
import apiEngine.IRestResponse;
import apiEngine.model.Book;
import apiEngine.model.requests.AddBooksRequest;
import apiEngine.model.requests.ISBN;
import apiEngine.model.requests.RemoveBookRequest;
import apiEngine.model.responses.Books;
import apiEngine.model.responses.UserAccount;
import cucumber.TestContext;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.When;
import enums.Context;
Page | 259
import io.restassured.response.Response;
super(testContext);
getScenarioContext().setContext(Context.BOOK, book);
getScenarioContext().setContext(Context.USER_ACCOUNT_RESPONSE, userAccountResponse);
Page | 260
Response response = getEndpoints().removeBook(removeBookRequest);
getScenarioContext().setContext(Context.BOOK_REMOVE_RESPONSE, response);
We will verify the responses saved in our ScenarioContext Objects as a part of this step. We will move all our
verification steps to a new class created as VerificationSteps.java.
Create a New Class and name it as VerificationSteps, by right-clicking on the stepDefinitions. After that, select New
>> Class.
VerificationSteps.java
package stepDefinitions;
import apiEngine.IRestResponse;
import apiEngine.model.Book;
import apiEngine.model.responses.UserAccount;
import cucumber.TestContext;
import cucumber.api.java.en.Then;
import enums.Context;
import io.restassured.response.Response;
import org.junit.Assert;
super(testContext);
Page | 261
Assert.assertTrue(userAccountResponse.isSuccessful());
Assert.assertEquals(201, userAccountResponse.getStatusCode());
Assert.assertEquals(userId, userAccountResponse.getBody().userID);
Assert.assertEquals(book.isbn, userAccountResponse.getBody().books.get(0).isbn);
Assert.assertEquals(204, response.getStatusCode());
Assert.assertEquals(200, userAccountResponse.getStatusCode());
Assert.assertEquals(0, userAccountResponse.getBody().books.size());
Explanation
• We just need to pass the Key to the getContext() method, which we can access
like scenarioContext.getContext(Key Name). Additionally, it will retrieve the value returned by the response
for Book.
• Since the method returns an object, we need to cast it to the right type. If it's cast it to a wrong type, the test
will fail here. So, we must be sure of the object type we stored for the respective key.
We are all set now to run the updated Cucumber test. Firstly, Right -Click on TestRunner class and Click Run
As >> JUnit Test. Cucumber runs the script in the same way as Selenium WebDriver. Consequently, the result will
display in the JUnit tab of the console.
Page | 262
Run the Tests from Cucumber Feature
To run the tests as a Cucumber Feature, right-click on the End2End_Test.feature file. Select the Run As>>Cucumber
Feature.
The tests passed successfully with the changes we made for sharing test data in Cucumber Steps using Scenario
Context in our framework.
Our updated project folder structure of the framework will look likewise:
In the next chapter, we will add Config Reader class for BaseUrl and UserId. Please try to implement the above
changes in your framework, as explained above.
As a solution to this, we will go for property file implementation in Java. If you wish to understand this on a
conceptual level, you could refer to the Read Configurations from Property File. Let us learn how to implement the
configurations from the property file.
Firstly, right-click on the root Project and select New >> Folder. Additionally, name it as configs. Moreover, we will
keep config files with in the same folder.
Secondly, right-click the above-created folder and select New >> File. Additionally, name it
as configuration.properties. Here, the .properties is the file extension.
Page | 264
Step 2: Write Hard-Coded Values to Property File
If we look at our TestContext.java class, we have been using two hardcoded values:
base_Url = http://bookstore.toolsqa.com
user_Id = 9b5f49ab-eea9-45f4-9d66-bcf56a531b85
Page | 265
Firstly, right-click on the src/test/java and select New >> Package. In addition to that, name it
as dataProvider. Moreover, all the data-readers files will be kept here in this package.
Secondly, right-click on the above created package and select New >> Class. After that, name it as ConfigFileReader.
ConfigReader.java
package configs;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
private ConfigReader() {
BufferedReader reader;
try {
try {
properties.load(reader);
reader.close();
} catch (IOException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
if(configReader == null) {
Page | 266
configReader = new ConfigReader();
return configReader;
Code Explanation:
properties.load(reader);
• propertyFilePath: It would be a String variable containing the information of the config file path.
• new Properties(): The Properties class represents a persistent set of properties. which can be saved to a
stream or loaded from it. Additionally, the key and the corresponding value in the property list is a string.
• properties.load(reader): It reads a property list of key and element pairs from the input character stream in a
simple line-oriented format.
If you have noticed the class ConfigReader.java, we have implemented it as a singleton class. The Singleton class’s
purpose is to control object creation, limiting the number of objects to only one. Additionally, there is only one
Singleton instance. Therefore, any instance fields of a Singleton would occur only once per class, similar to static
fields.
Page | 267
Singleton pattern ensures the creation of only one instance of a class in the JVM. Moreover, it enables a global point
of access to the object. In our case, we have ConfigReader.java, which should be accessed globally. So it is better to
make the ConfigReader.java class as a singleton.
The common concepts among several approaches to implement a Singleton pattern are:
• Private constructor
// ConfigReader class
private ConfigReader() {
if (configReader == null) {
return configReader;
The ConfigReader.java class maintains a static reference to its instance. Additionally, it returns that reference from
the static getInstance() method.
ConfigFileReader Method
properties.getBaseUrl(): Properties object gives us a .getProperty method. Additionally, the input is Key of the
property sent as a parameter while the Value of the matched key is the output from the .properties file.
Page | 268
Moreover, if the properties file doesn't have the specified key, it returns the null. Hence, we have to put the null
check and, in case of null, throw an exception to stop the test with stack trace information.
For more details, you can visit the article on Singleton Pattern in Java.
After making the necessary changes for the BASE_URL and USER_ID inTextContext.java class:
public TestContext() {
scenarioContext.setContext(Context.USER_ID, USER_ID);
package cucumber;
import apiEngine.EndPoints;
import configs.ConfigReader;
import enums.Context;
public TestContext() {
scenarioContext.setContext(Context.USER_ID, ConfigReader.getInstance().getUserID());
return endPoints;
return scenarioContext;
Page | 269
Step 5: Run the Cucumber Test
We are all set now to run the updated Cucumber test. Firstly, Right -Click on ***TestRunner *class and Click Run
As >> JUnit Test. Cucumber runs the script in the same way as Selenium WebDriver. Finally, the result will display in
the JUnit tab of the console.
To run the tests as a Cucumber Feature, right-click on the End2End_Test.feature file. Select the Run As>>Cucumber
Feature.
Moreover, please try to implement the above changes in your framework, as explained above. Subsequently, our
updated project folder structure of the framework will look likewise:
The tests passed successfully with the changes we made to the Configuration Reader in our framework.
Page | 270
Rest Assured Examples
We have seen all the types of HTTP requests so far with respect to Rest Assured. Since these requests are distributed
in various tutorials, a collective reference can serve as a bookmark for our readers as they get their hands dirty with
rest assured. In this short post, we have combined rest assured examples with various HTTP requests with hands-on
code for each of them. This is also reflected in the index as below:
Rest Assured API supports functionality for various HTTP Requests like GET, POST, PUT, DELETE. Let us briefly discuss
each of these methods and also walkthrough implementation of each method in Rest Assured.
The HTTP GET request is used widely in the API world. We can use this request to fetch/get a resource from a server
without sending any data with our requests. Since we are focusing on examples only in this post, you can refer to the
GET request post here.
Let us now implement the GET request using Rest Assured. The code for the same is shown below.
import io.restassured.RestAssured;
import io.restassured.http.Method;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
@Test
RestAssured.baseURI = "https://demoqa.com/BookStore/v1/Books";
//In this case the request does not take any parameters
// Print the status and message body of the response received from the server
System.out.println("Response=>" + response.prettyPrint());
Page | 271
}
In the above code, we send a GET request to fetch the list of books and details of each book.
Suppose we want to post/send some data on the server or create a resource on the server, then we go for an HTTP
POST request. For more information on the same, you can refer to Understanding HTTP POST Request Method
using Rest Assured for more details.
The following code implements the HTTP POST request using Rest Assured.
RestAssured.baseURI = "https://demoqa.com";
requestParams.put("userId", "TQ123");
requestParams.put("isbn", "9781449325862");
Here we post a request to BookStore and get the response from the API.
The HTTP PUT request either update a resource or substitutes the representation of the target resource with the full
JSON request payload. For a detailed discussion on HTTP PUT requests, visit PUT Request using Rest Assured.
import org.testng.Assert;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import io.restassured.response.ResponseBody;
Page | 272
import io.restassured.specification.RequestSpecification;
String baseUrl="https://demoqa.com";
String token =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyTmFtZSI6InRlc3RpbmcxMjMiLCJwYXNzd29yZCI6IlBhc3N3b3JkQDEiL
CJpYXQiOjE2Mjg1NjQyMjF9.lW8JJvJF7jKebbqPiHOBGtCAus8D9Nv1BK6IoIIMJQ4";
@Test
RestAssured.baseURI = baseUrl;
.header("Content-Type", "application/json");
Response res = httpRequest.body("{ \"isbn\": \"" + isbn + "\", \"userId\": \"" + userId +
"\"}").put("/BookStore/v1/Book/9781449325862");
//Fetching the response code from the request and validating the same
Assert.assertEquals(res.getStatusCode(),200);
Here, we update the book record with the given ISBN value by setting a new ISBN value and also setting the userId
value.
We can delete a resource from a server by making a DELETE request. We have a detailed description of the DELETE
request in the article, DELETE Request using Rest Assured.
The following Rest assured example demonstrates the working of HTTP DELETE Request.
package bookstore;
import org.testng.Assert;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
Page | 273
import org.testng.annotations.Test;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import io.restassured.response.ResponseBody;
import io.restassured.specification.RequestSpecification;
String baseUrl="https://demoqa.com";
String token =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyTmFtZSI6InRlc3RpbmcxMjMiLCJwYXNzd29yZCI6IlBhc3N3b3JkQDEiL
CJpYXQiOjE2Mjg1NjQyMjF9.lW8JJvJF7jKebbqPiHOBGtCAus8D9Nv1BK6IoIIMJQ4";
@Test
RestAssured.baseURI = baseUrl;
.header("Content-Type", "application/json");
Response res = httpRequest.body("{ \"isbn\": \"" + isbn + "\", \"userId\": \"" + userId +
"\"}").delete("/BookStore/v1/Book");
//Fetching the response code from the request and validating the same
Assert.assertEquals(res.getStatusCode(),204);
The above code is for the HTTP DELETE request. Here we pass the ISBN and the userId for which the resource is to be
deleted. The response obtained confirms the deletion (or if not).
Page | 274