In our previous chapter, we introduced the concept of using an Endpoints class in our framework. As a means to abstract the logic of communication with the server into a separate class and to make our steps cleaner, we introduced this Endpoints class. Subsequently, in this chapter, we are going to take it a step further by introducing the REST Routes concept in our framework. As you all know, we use an API endpoint to carry out a specific task. Moreover, Routes are the paths through which we can access the endpoints. In simpler terms, we call the route as URI, while an endpoint is an action we perform on the URI.

What are REST Routes in API?

As we know, client-server communication is one of the REST (representational state transfer) principles. Additionally, it provides a mapping between the HTTP verbs like GET, PUT, POST, DELETE, etc. with CRUD(create, read, update, and delete) operations. We click on links and navigate through various sites. Moreover, in this process, we are merely making a state transition when we navigate to one site from another. The REST-compliant systems are often referred to as RESTful systems.

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.

For example in the URL,

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:

GET- http://bookstore.toolsqa.com/BookStore/v1/Books To fetch a list of books
POST- http://bookstore.toolsqa.com/BookStore/v1/Books To add a book associated with the user
DELETE - http://bookstore.toolsqa.com/BookStore/v1/Books To remove books associated with the user

It is how the endpoints looked in our Swagger Bookstore API

REST Routes- BookStore APIs

Implementation of REST Routes in Framework

We will follow the steps below to implement Routes in our framework:

  1. Firstly, Create a Route class
  2. Secondly, Modify the Endpoints class
  3. Thirdly, Run the tests

Create a Route class

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.

  2. After that, add the following code snippet to it:

package apiEngine;

public class Route {

    private static final String BOOKSTORE = "/BookStore";
    private static final String ACCOUNT = "/Account";
    private static final String VERSION = "/v1";
    
    
    public static String generateToken(){
    	return ACCOUNT + VERSION + "/GenerateToken";
    }

    public static String books(){ 
    	return BOOKSTORE + VERSION + "/Books";
    }

    public static String book(){ 
    	return BOOKSTORE + VERSION + "/Book";
    }

    public static String userAccount(String userId){
    	return ACCOUNT + VERSION + "/User" + "/" + userId; 
    }

}

Modify the Endpoints class for REST Routes

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:

Our method authenticateUser() is updated from:

public static Response authenticateUser(AuthorizationRequest authRequest) {
	RestAssured.baseURI = BASE_URL;
        RequestSpecification request = RestAssured.given();

        request.header("Content-Type", "application/json");
       //The hardcoded route "/Account/vi/GenerateToken" will be modified to take the route from the Route class
        Response response = request.body(authRequest).post("/Account/v1/GenerateToken");
        return response;
	}

to

public static Response authenticateUser(AuthorizationRequest authRequest) {
	RestAssured.baseURI = BASE_URL;
        RequestSpecification request = RestAssured.given();

        request.header("Content-Type", "application/json");
        Response response = request.body(authRequest).post(Route.generateToken());
        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".

Similarly, we update the below methods for the Endpoints class:

  1. getBooks()
  2. addBook()
  3. removeBook()
  4. getUserAccount()

Consequently, our updated Endpoints class will look likewise:

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;

public class EndPoints {
	
    private static final String BASE_URL = "https://bookstore.toolsqa.com";

    public static Response authenticateUser(AuthorizationRequest authRequest) {
	RestAssured.baseURI = BASE_URL;
        RequestSpecification request = RestAssured.given();

        request.header("Content-Type", "application/json");
        Response response = request.body(authRequest).post(Route.generateToken());
        return response;
    }

    public static Response getBooks() {
        RestAssured.baseURI = BASE_URL;
        RequestSpecification request = RestAssured.given();

        request.header("Content-Type", "application/json");
        Response response = request.get(Route.books());
        return response;
    }

    public static Response addBook(AddBooksRequest addBooksRequest, String token) {
        RestAssured.baseURI = BASE_URL;
        RequestSpecification request = RestAssured.given();
        request.header("Authorization", "Bearer " + token)
                .header("Content-Type", "application/json");

        Response response = request.body(addBooksRequest).post(Route.books());
        return response;
    }

    public static Response removeBook(RemoveBookRequest removeBookRequest, String token) {

        RestAssured.baseURI = BASE_URL;
        RequestSpecification request = RestAssured.given();

        request.header("Authorization", "Bearer " + token)
                .header("Content-Type", "application/json");

        Response response = request.body(removeBookRequest).delete(Route.book());
        return response;
    }

    public static Response getUserAccount(String userId, String token) {

        RestAssured.baseURI = BASE_URL;
        RequestSpecification request = RestAssured.given();

        request.header("Authorization", "Bearer " + token)
                .header("Content-Type", "application/json");

        Response response = request.get(Route.userAccount(userId));
        return response;
    }

}

Run the Cucumber Test

Run the Tests as JUnit

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.

Implementation of REST Routes Junit Results

Run the Tests from Cucumber Feature

To run the tests as a Cucumber Feature, right-click on the End2End_Test.feature file. After that, select the Run As>>Cucumber Feature.

Image: Chapter 6 Implementation of Routes Cucumber Results

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:

Images: Chapter 6 Implementation of Routes in Endpoints Project Structure

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.

Separation of Test Layer with API Services
Separation of Test Layer with API Services
Previous Article
Implementation of Generics in API Framework
Implementation of Generics in API Framework
Next Article

Similar Articles

Feedback