Rest Assured Basics
Agenda
To cover basic concepts of rest-assured framework, that will enable us to achieve API automation.
Introduction
- API(Application Programming Interface) is an interface between client and server, which makes a request in specific format and gets response in a specific format.
Terminology
- Endpoint/base uri : Address where API is hosted
- GET, POST, PUT, DELETE --> common methods to interact with REST API's, often we call them as CRUD operations (Create, Retrieve, Update, Delete)
- GET --> used to extract data from server
- POST --> used to send data to server
- PUT --> to replace existing resources on server
- DELETE --> to delete a resource on server
- Resource --> more of a package under endpoint.
- google/maps, google/docs --> where maps and docs are resources.
- Parameters
- Path Parameters: points to specific resource within a collection
- https://google.com/images/123
- Query Parameters: used to sort or filter the resources
- https://amazon.com/orders?sort_by=4/28/2022
- API might look like endpoint/resource/(query/path parameters)
- Headers/Cookies --> it's more like meta data(additional data) associated API request and response.
- Example: Authorization details
Rest Assured
- have maven dependencies for rest-assured, hamcrest and testng into your project
<dependencies>
<!-- https://mvnrepository.com/artifact/io.rest-assured/rest-assured -->
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>5.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.testng/testng -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hamcrest/hamcrest -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>2.2</version>
</dependency>
</dependencies>
Scenario
Add place --> update place --> get place
Add place API
given() --> captures all request inputs
when() --> submits the api with resource
then() --> for any validations
Simple code to validate api response for 200 status code
Request:
Request method: POST
Request URI: https://name.com/maps/api/place/add/json?key=qaclick123
Proxy: <none>
Request params: <none>
Query params: key=qaclick123
Form params: <none>
Path params: <none>
Headers: Accept=*/*
Content-Type=application/json
Cookies: <none>
Multiparts: <none>
Body:
{
"location": {
"lat": -38.383494,
"lng": 33.427362
},
"accuracy": 50,
"name": "Frontline house",
"phone_number": "(+91) 983 893 3937",
"address": "29, side layout, cohen 09",
"types": [
"shoe park",
"shop"
],
"website": "http://google.com",
"language": "French-IN"
}
Response:
{
"status": "OK",
"place_id": "c7fde72466f72961cd578baf63ae8a8f",
"scope": "APP",
"reference": "ca17b2d14af2ac425711cf37a61078feca17b2d14af2ac425711cf37a61078fe",
"id": "ca17b2d14af2ac425711cf37a61078fe"
}
Code:
public void testAddPlace(){
RestAssured.baseURI = "https://name.com";
given().log().all().queryParam("key", "qaclick123").header("Content-Type", "application/json")
.body("{\n" +
" \"location\": {\n" +
" \"lat\": -38.383494,\n" +
" \"lng\": 33.427362\n" +
" },\n" +
" \"accuracy\": 50,\n" +
" \"name\": \"Frontline house\",\n" +
" \"phone_number\": \"(+91) 983 893 3937\",\n" +
" \"address\": \"29, side layout, cohen 09\",\n" +
" \"types\": [\n" +
" \"shoe park\",\n" +
" \"shop\"\n" +
" ],\n" +
" \"website\": \"http://google.com\",\n" +
" \"language\": \"French-IN\"\n" +
"}").when().post("maps/api/place/add/json")
.then().log().all().assertThat().statusCode(200);
}
Lets add assertions to above code
.then().log().all().assertThat().statusCode(200)
.body("scope", equalTo("APP"))
.header("Server", "Apache/2.4.41 (Ubuntu)");
Extract data
.extract().response().asString();use a variable to capture response.
Parse json using JsonPath class and extract place
{
"status": "OK",
"place_id": "201e0f6b1fa6a2cc7500c9b2df199898",
"scope": "APP",
"reference": "35a4897fa87e3db6f0f8017a7faf63a835a4897fa87e3db6f0f8017a7faf63a8",
"id": "35a4897fa87e3db6f0f8017a7faf63a8"
}
JsonPath jsonPath = new JsonPath(response);
String place = jsonPath.getString("place_id");
update place
Request:
Request method: PUT
Request URI: https://name.com/maps/api/place/update/json?key=qaclick123
Proxy: <none>
Request params: <none>
Query params: key=qaclick123
Form params: <none>
Path params: <none>
Headers: Accept=*/*
Content-Type=application/json
Cookies: <none>
Multiparts: <none>
Body:
{
"place_id": "c7fde72466f72961cd578baf63ae8a8f",
"address": "70 winter walk, USA",
"key": "qaclick123"
}
Response:
{
"msg": "Address successfully updated"
}
given().log().all().queryParam("key", "qaclick123").header("Content-Type", "application/json")
.body("{\n" +
"\"place_id\":\""+place+"\",\n" +
"\"address\":\"70 winter walk, USA\",\n" +
"\"key\":\"qaclick123\"\n" +
"}").when().put("maps/api/place/update/json")
.then().log().all().assertThat().statusCode(200)
.body("msg", equalTo("Address successfully updated"));
Get place and validate address
String getResponse = given().log().all().queryParam("key", "qaclick123").queryParam("place_id", place)
.when().get("maps/api/place/get/json")
.then().log().all().assertThat().statusCode(200)
.extract().response().asString();
jsonPath = new JsonPath(getResponse);
String currentAddress = jsonPath.getString("address");
Assert.assertTrue(currentAddress.equalsIgnoreCase(newAddress), "Address mismatch");
Traversing json
Lets take a look at complex json
{
"dashboard": {
"purchaseAmount": 1162,
"website": "name.com"
},
"courses": [
{
"title": "Selenium Python",
"price": 50,
"copies": 6
},
{
"title": "Cypress",
"price": 40,
"copies": 4
},
{
"title": "RPA",
"price": 45,
"copies": 10
},
{
"title": "Appium",
"price": 36,
"copies": 7
}
]
}
get Number of courses
String count = jsonPath.getString("courses.size()");
System.out.println("course size : "+count);
print purchase amount
String purchaseAmount = jsonPath.getString("dashboard.purchaseAmount");
System.out.println("Purchase amount is "+purchaseAmount);
get title of first course
String title = jsonPath.getString("courses[0].title");
System.out.println("title of course is : "+title);
print all courses and their respective titles
for(int i=0; i<count; i++){
System.out.println("title of course is : "+jsonPath.getString("courses["+i+"].title"));
}
Parse json file to string
Read all the bytes and convert to a string
System.out.println(new String(Files.readAllBytes(Paths.get(System.getProperty("user.dir")+"//src/test//resources//complex.json"))));
Cookie based Authentication
- invoke an endpoint that creates a session id with your login credentials
- this session id, will be used as a cookie in header parameters for any request
Adding path parameter
endpoint: https://localhost:8080/slab/id/{125}/price
observe key is parameterized
given().pathParams("key", "123").log().all().header("Content-Type", "application/json")
.body(PayLoads.getAddPlacePayload()).when().post("slabs/id/{key}/price")
Capturing session using session filter
- one of way capturing session from the response is by using jsonpath and get the session value
- other way, is by using SessionFilter class and using filter method, which will have the knowledge of session.
given().pathParams("key", "123").log().all().header("Content-Type", "application/json")
.body(PayLoads.getAddPlacePayload()).filter(sessionFilter).when().post("slabs/id/{key}/price")
file attachment using multipart
observe how header and multipart methods are configured
given().pathParams("key", "123").log().all().
header("Content-Type", "multipart/form-data")
.body(PayLoads.getAddPlacePayload()).filter(sessionFilter).
multiPart("file", new File("java.txt")).when().post("slabs/id/{key}/price")
url encoding false
if there are special characters in your url, to handle it use below command
given().urlEncodingEnabled(false)
https certificate issue
we can relax these issues by
given().relaxedHTTPSValidation().OAuth2.0 Authorization
- comes with multiple grant types, most commonly used are Authorization code and client credentials.
Authorization code grant type
details that are needed from client
client id, client secret, resource owner, resource/authorization server
Ex: bookmyshow, client id, client secret, me, Google
in detail,
- client sends client id and secret to authorization server and gets authorization code.
- using this authorization code, call will be invoked to resource server to get access code and other details
- this access token will be used for all calls.
Note: scope of token can be increased
client credentials grant type
here Application request for client credentials from resource server
Example: integrating twitter into your website
Note: In postman, there is a option to generate new token in OAuth2.0 mechanism, you can check for your reference.
Serializing and de-serializing json
have the dependencies downloaded
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.13.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.0</version>
</dependency>
Lets de-serialize
Runner class
GetPlace getPlace = given().log().all().queryParam("key", "qaclick123").
queryParam("place_id", place).expect().defaultParser(Parser.JSON)
.when().get("maps/api/place/get/json")
.then().log().all().assertThat().statusCode(200)
.extract().as(GetPlace.class);
System.out.println(getPlace.getAccuracy());
GetPlace class
package day3;
public class GetPlace {
private Location location;
private String accuracy;
private String name;
private String phone_number;
private String address;
private String types;
private String website;
private String language;
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public String getAccuracy() {
return accuracy;
}
public void setAccuracy(String accuracy) {
this.accuracy = accuracy;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone_number() {
return phone_number;
}
public void setPhone_number(String phone_number) {
this.phone_number = phone_number;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getTypes() {
return types;
}
public void setTypes(String types) {
this.types = types;
}
public String getWebsite() {
return website;
}
public void setWebsite(String website) {
this.website = website;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
}
Location class
package day3;
public class Location {
private String latitude;
private String longitude;
public String getLatitude() {
return latitude;
}
public void setLatitude(String latitude) {
this.latitude = latitude;
}
public String getLongitude() {
return longitude;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
}
json
{
"location": {
"latitude": "-38.383494",
"longitude": "33.427362"
},
"accuracy": "50",
"name": "Frontline house",
"phone_number": "(+91) 983 893 3937",
"address": "29, side layout, cohen 09",
"types": "shoe park,shop",
"website": "http://google.com",
"language": "French-IN"
}Let's Serialize
driver class
AddPlace addPlace = new AddPlace();
addPlace.setAccuracy("50");
addPlace.setName("vinay");
addPlace.setPhone_number("(+91) 983 893 3937");
addPlace.setAddress("vinay, side layout, cohen 09");
List<String> types = new ArrayList<>();
types.add("shoe park");
types.add("shop");
addPlace.setTypes(types);
addPlace.setWebsite("http://google.com");
addPlace.setLanguage("French-IN");
Location location = new Location();
location.setLat("-38.383494");
location.setLng("33.427362");
addPlace.setLocation(location);
RestAssured.baseURI = "https://name.com";
String response = given().log().all().queryParam("key", "qaclick123")
.header("Content-Type", "application/json")
.body(addPlace).when().post("maps/api/place/add/json")
.then().log().all().assertThat().statusCode(200)
.body("scope", equalTo("APP"))
.header("Server", "Apache/2.4.41 (Ubuntu)")
.extract().response().asString();
Add place class
package day3.serialize.pojo;
import java.util.List;
public class AddPlace {
private String accuracy, name, phone_number, address, website, language;
private Location location;
private List<String> types;
public String getAccuracy() {
return accuracy;
}
public void setAccuracy(String accuracy) {
this.accuracy = accuracy;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone_number() {
return phone_number;
}
public void setPhone_number(String phone_number) {
this.phone_number = phone_number;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getWebsite() {
return website;
}
public void setWebsite(String website) {
this.website = website;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public List<String> getTypes() {
return types;
}
public void setTypes(List<String> types) {
this.types = types;
}
}
Location class
package day3.serialize.pojo;
public class Location {
private String lat, lng;
public String getLat() {
return lat;
}
public void setLat(String lat) {
this.lat = lat;
}
public String getLng() {
return lng;
}
public void setLng(String lng) {
this.lng = lng;
}
}
json
{
"location": {
"lat": -38.383494,
"lng": 33.427362
},
"accuracy": 50,
"name": "Frontline house",
"phone_number": "(+91) 983 893 3937",
"address": "29, side layout, cohen 09",
"types": [
"shoe park",
"shop"
],
"website": "http://google.com",
"language": "French-IN"
}Spec builders
common code in request and response can be added in spec builders, so that it can be reused.
RequestSpecification requestSpecification = new RequestSpecBuilder().setBaseUri("https://name.com")
.addQueryParam("key", "qaclick123")
.setContentType(ContentType.JSON).build();
ResponseSpecification responseSpecification = new ResponseSpecBuilder().
expectStatusCode(200).
expectContentType(ContentType.JSON).
expectHeader("Server", "Apache/2.4.41 (Ubuntu)").build();
RequestSpecification request = given().log().all().spec(requestSpecification).body(addPlace);
String response = request.when().post("maps/api/place/add/json")
.then().log().all()
.assertThat().spec(responseSpecification)
.body("scope", equalTo("APP"))
.extract().response().asString();
JsonPath jsonPath = new JsonPath(response);
String place_id = jsonPath.getString("place_id");
System.out.println("Place id is "+place_id);
Logging
logging can be done to a file
addFilter(RequestLoggingFilter.logRequestTo(new PrintStream(new FileOutputStream("logging.txt"))))
.addFilter(ResponseLoggingFilter.logResponseTo(new PrintStream(new FileOutputStream("logging.txt"))))
run TestRunner via maven
- you can run TestRunner from maven with simple command mvn test by navigating to project folder
- you can pass arguments as well mvn test -Dcucumber-options="--tags=@AddPlaceAPI"
maven cucumber reporting
please refer to this link - damianszczepanik/maven-cucumber-reporting: maven mojo for cucumber reporting (github.com)
Resources
Please refer to my github project for more details - itsvinayr/rest-assured-basics: Covers basic concepts in rest assured to achieve mobile automation (github.com)
Please refer to my git hub project for framework - itsvinayr/api-cucumber-framework: E2E API automation framework developed with rest-assured and cucumber frameworks. (github.com)
Comments
Post a Comment