REST Assured Framework Design

A well-designed REST Assured framework follows a layered and modular architecture where each layer has a specific responsibility. This separation improves reusability, maintainability, scalability, and readability.

Interview Answer

"I designed the REST Assured framework using a layered architecture by separating API logic, test logic, configuration, utilities, test data, and reporting. This modular approach reduces code duplication, improves maintainability, and allows easy scaling as the project grows."


Advertisement

REST Assured Framework Architecture

                 Test Layer
                     │
                     ▼
            Service / Request Layer
                     │
                     ▼
                Base Layer
                     │
      ┌──────────────┴──────────────┐
      ▼                             ▼
 Utility Layer                 Data Layer
      │                             │
      └──────────────┬──────────────┘
                     ▼
              Reporting Layer

Typical Project Structure

RESTAssuredFramework
│
├── src/test/java
│   ├── base
│   │      BaseTest.java
│   │
│   ├── tests
│   │      LoginTests.java
│   │      UserTests.java
│   │      ProductTests.java
│   │
│   ├── services
│   │      LoginService.java
│   │      UserService.java
│   │      ProductService.java
│   │
│   ├── utils
│   │      JsonUtility.java
│   │      ExcelUtility.java
│   │      RetryAnalyzer.java
│   │
│   ├── pojo
│   │      LoginRequest.java
│   │      UserRequest.java
│   │
│   └── reports
│          ExtentManager.java
│
├── src/test/resources
│      config.properties
│      qa.properties
│      uat.properties
│      payload.json
│
├── pom.xml
└── testng.xml

Layers in the REST Assured Framework

Each layer has one responsibility.

Layer Responsibility
Test Layer Test cases and assertions
Service / Request Layer API request methods (GET, POST, PUT, DELETE)
Base Layer Common configuration (Base URI, authentication, headers)
Utility Layer Reusable helper methods
Data Layer Test data management (JSON, POJO, Excel)
Reporting Layer Execution reports (Extent Reports, Allure)

1. Test Layer

The Test Layer contains all test cases and validations.

Responsibilities:

  • Execute API tests
  • Call service methods
  • Validate responses
  • Perform assertions
  • Verify status codes

Example:

@Test
public void verifyUserDetails() {

    Response response = UserService.getUser(10);

    response.then()
            .statusCode(200);

    Assert.assertEquals(
            response.jsonPath().getString("name"),
            "John");
}

2. Service / Request Layer

This layer contains reusable API request methods.

Instead of writing REST Assured code in every test, all requests are centralized here.

Responsibilities

  • GET requests
  • POST requests
  • PUT requests
  • DELETE requests

Example

public class UserService {

    public static Response getUser(int id){

        return given()
                .pathParam("id", id)
        .when()
                .get("/users/{id}");
    }

}

Advantages

  • Reusable methods
  • Cleaner tests
  • Easier maintenance

3. Base Layer

The Base Layer contains common framework configuration.

Responsibilities

  • Base URI
  • Base Path
  • Authentication
  • Common Headers
  • Request Specification

Example

public class BaseTest {

    protected RequestSpecification request;

    @BeforeMethod
    public void setup(){

        request = given()
                    .baseUri(ConfigReader.getBaseUrl())
                    .contentType(ContentType.JSON);

    }

}

Why Use a Base Layer?

Without a Base Layer:

given()
.baseUri("https://qa.myapi.com")

would be repeated in every test.

With a Base Layer:

request
.when()
.get("/users");

No duplication.


Utility Layer

Utility classes contain reusable helper methods.

Examples

  • Reading JSON files
  • Reading Excel
  • Date generation
  • Random data generation
  • Retry mechanism
  • Property reader

Example

String randomEmail = RandomUtility.generateEmail();

Benefits

  • Avoid duplicate code
  • Easy reuse
  • Better readability

Data Layer

The Data Layer manages test data.

Instead of writing payloads directly in Java code, data is stored externally.

Common approaches

  • JSON Files
  • POJO Classes
  • Excel Files
  • CSV Files
  • Database
  • TestNG DataProviders

JSON Payload Example

{
   "name":"John",
   "job":"Tester"
}

POJO Example

public class User {

    private String name;
    private String job;

    // Getters and Setters

}

Benefits

  • Data-driven testing
  • Reusable payloads
  • Easy maintenance
  • No hardcoding

Reporting Layer

The Reporting Layer generates execution reports.

Popular tools

  • Extent Reports
  • Allure Reports
  • TestNG Reports

Reports include

  • Passed Tests
  • Failed Tests
  • Execution Time
  • Request Details
  • Response Details
  • Screenshots (if applicable)
  • Error Messages

Why Use Layers?

Layered architecture provides several advantages.

  • Easy maintenance
  • Better code organization
  • High reusability
  • Minimal code duplication
  • Easy debugging
  • Supports large projects
  • Easy onboarding for new team members

Real-Time Example

Suppose a Login API returns:

Status Code : 200
JWT Token

The Test Layer verifies the response.

The Service Layer performs the login request.

The Base Layer provides the Base URI and headers.

The Utility Layer extracts the JWT token.

The Reporting Layer logs the execution.


Base URI and Base Path

REST Assured provides two commonly used properties.

Base URI

The Base URI represents the common domain.

Example

https://qa.myapi.com

Base Path

The Base Path represents the common API path.

Example

/employee

Instead of writing

https://qa.myapi.com/employee

every time, configure:

RestAssured.baseURI = "https://qa.myapi.com";
RestAssured.basePath = "/employee";

Then simply call:

given()
.when()
.get("/1");

REST Assured automatically combines them.


Real-Time Example

When moving from:

QA

to

UAT

only the configuration changes.

No automation code changes are required.


Advantages

  • No hardcoded URLs
  • Easy environment switching
  • Cleaner code
  • Better maintainability

Avoiding Hardcoded Values

Hardcoding means directly writing fixed values in the source code.

Avoid hardcoding values such as:

  • Base URLs
  • Credentials
  • Endpoints
  • Tokens
  • User IDs
  • Test Data

Use Configuration Files

Example:

baseUrl=https://qa.myapi.com
username=qa_admin
# no password here — read it from an environment variable or the CI credential store
String password = System.getenv("API_PASSWORD");

Configuration files are committed to Git, so they must never hold real passwords, tokens or API keys. Inject secrets at run time from environment variables or Jenkins/GitHub credentials.

Read values using:

ConfigReader.getProperty("baseUrl");

Store Test Data Externally

Instead of

String name="John";

Read from

  • JSON
  • Excel
  • Database
  • CSV
  • POJO

Environment Selection

Use

  • TestNG Parameters
  • Maven Profiles
  • Properties Files

for QA, UAT, Stage, and Production environments.


Benefits

  • One place to update values
  • No code changes
  • Easy maintenance
  • Better scalability

Managing Test Data

Test data should always be stored outside the code.

Common approaches

JSON Files

{
  "name":"David",
  "job":"Developer"
}

POJO Classes

Convert request payloads into Java objects.


Excel

Useful for

  • Multiple users
  • Bulk testing
  • Regression data

TestNG DataProvider

Run the same test using multiple data sets.

Example

@DataProvider
public Object[][] loginData(){

    return new Object[][]{

        {"admin","admin123"},
        {"user","user123"}

    };

}

Benefits

  • Data-driven testing
  • Less duplicate code
  • Reusable data
  • Easy updates

Handling Multiple Environments

Large projects usually have multiple environments.

Examples

  • QA
  • UAT
  • Stage
  • Production

Instead of changing URLs manually, store them in configuration files.

Example

qa.baseUrl=https://qa.myapi.com

uat.baseUrl=https://uat.myapi.com

Use

  • Maven Profiles
  • TestNG Parameters
  • Environment Variables

to select the required environment.


Benefits

  • No code modifications
  • Fast switching
  • Safer deployments
  • Better automation

Logging Requests and Responses

Logging helps identify issues quickly by capturing complete request and response details.


Request Logging

given()
.log().all()
.when()
.post("/users");

Logs

  • URL
  • Headers
  • Parameters
  • Body

Response Logging

response.then()
.log().all();

Logs

  • Status Code
  • Headers
  • Response Body
  • Response Time

Log Only the Response Body

response.then()
.log().body();

Using Log4j

Framework-level logging is typically handled using Log4j.

Example

logger.info("User created successfully");
logger.error("Login API failed");

Using REST Assured Filters

Filters capture complete request and response information centrally.

Useful for

  • CI/CD
  • Debugging
  • Audit Logs

Real-Time Example

I always log the request headers, request body, response body, status code, and response time. During one failure, the logs showed that a mandatory request field was missing, allowing us to identify the root cause quickly. Related: Logging & Response Extraction in REST Assured.


Why Logging is Important

  • Faster debugging
  • Root cause analysis
  • CI/CD troubleshooting
  • Better reports
  • Easier defect investigation

Reporting

Reporting summarizes automation execution results for testers, developers, and stakeholders.


  • Extent Reports
  • Allure Reports
  • TestNG Reports

Report Includes

  • Test Name
  • Execution Time
  • Pass/Fail Status
  • Request Details
  • Response Details
  • Failure Reason
  • Logs
  • Exception Stack Trace

Advantages

  • Easy-to-read execution results
  • Better communication with stakeholders
  • Faster failure analysis
  • Historical execution tracking

Connecting the Layers: A Minimal Working Example

The snippets above show each layer on its own. Here's how they connect — the base layer builds one specification, the service layer uses it, and the test only asserts:

// Base layer
public abstract class BaseTest {
    protected static RequestSpecification spec;

    @BeforeSuite(alwaysRun = true)
    public void buildSpec() {
        RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
        spec = new RequestSpecBuilder()
                .setBaseUri(ConfigReader.get("baseUrl"))
                .setBasePath("/api/v1")
                .setContentType(ContentType.JSON)
                .addHeader("Authorization", "Bearer " + TokenManager.getToken())   // utility layer
                .build();
    }
}

// Service layer
public class UserService {
    public static Response getUser(int id) {
        return given().spec(BaseTest.spec).pathParam("id", id).get("/users/{id}");
    }
    public static Response createUser(User user) {                            // data layer: a POJO
        return given().spec(BaseTest.spec).body(user).post("/users");
    }
}

// Test layer
public class UserTests extends BaseTest {
    @Test
    public void createdUserCanBeRead() {
        User user = new User("QA " + System.currentTimeMillis(), "Tester");
        int id = UserService.createUser(user).then().statusCode(201).extract().path("id");

        UserService.getUser(id).then()
            .statusCode(200)
            .body("name", equalTo(user.getName()));
    }
}

Using a static RequestSpecification built once is safe for parallel runs because tests only read it. A @BeforeMethod that rebuilds the request for every test (as in the Base Layer example above) also works but repeats setup; if different tests need different users, give the service methods a spec parameter instead. Watch a request pass through each layer in the REST Assured Visualizer.

From Real Projects

My API experience covers CRUD operations, HTTP methods, JSON path, and validating JSON and XML responses, and my automation work was in Java with TestNG. That combination is exactly what REST Assured builds on: HTTP calls in Java, JSON path for extracting values, and TestNG for running and grouping the tests. If you already know Selenium with TestNG, REST Assured fits into the same project structure. Testsigma supports web, mobile and API test automation, so understanding APIs was part of understanding the product I was testing. Keep request specifications, data and assertions in separate layers. A closely related topic: Practice REST Assured CI/CD, Contract & Senior Tasks.

📚 Official documentation: REST Assured official site · MDN: HTTP

Frequently Asked Questions (FAQs)

1. How did you design your REST Assured framework?

I designed it using a layered, modular architecture that separates test logic, API requests, configuration, utilities, test data, and reporting. This improves reusability, scalability, and maintainability.


2. What layers are included in your API framework?

The framework consists of:

  • Test Layer
  • Service/Request Layer
  • Base Layer
  • Utility Layer
  • Data Layer
  • Reporting Layer

Each layer has a single, well-defined responsibility.


3. What are baseURI and basePath?

  • baseURI is the common domain of the API (for example, https://qa.myapi.com).
  • basePath is the common resource path (for example, /employee).

Configuring them centrally allows easy switching between environments without changing test code.


4. How do you avoid hardcoded values?

I externalize values using:

  • config.properties for URLs, credentials, and endpoints
  • JSON files or POJO classes for test data
  • TestNG parameters or Maven profiles for environment selection

This makes the framework configurable and easier to maintain.


5. How do you manage test data?

I use:

  • JSON files
  • POJO classes
  • Excel files
  • TestNG DataProviders

These approaches support reusable and data-driven API tests.


6. How do you log requests and responses?

I use:

  • REST Assured's .log().all() and .log().body()
  • REST Assured Filters for centralized logging
  • Log4j for framework-level logging

I capture request headers, request body, response body, status code, and response time to simplify debugging and CI/CD analysis.


7. How do you report API automation results?

I use a Reporting Layer with tools such as Extent Reports or Allure Reports, along with TestNG reports. These reports include pass/fail status, execution time, request and response details, logs, and failure reasons, making it easier for teams to analyze test execution.