Advanced API Testing

This is Part 1 of the REST Assured Practice Roadmap — the work a new API automation engineer does in their first two sprints. Sprint 0 is understanding the API and deciding what to automate; Sprint 1 is building the framework and a first smoke suite. Each part lists the exercises, then gives worked examples and starter code, using Fake Store API as the practice project.

Advertisement

Sprint 0 — Understand the API Before Automating

Most failed API automation projects skip this step and automate whatever is easiest. Spend the first sprint answering: what exists, what matters, and what should be automated first?

Exercises

  1. List every endpoint from the documentation (Swagger/OpenAPI, Postman collection or network calls).
  2. Group them by module — auth, products, users, carts, orders.
  3. Mark public vs secured endpoints and the auth each needs.
  4. Map dependencies — which calls need data from others (login → token → cart).
  5. Rank business criticality — what breaks revenue or trust if it fails?
  6. Pick smoke APIs — a handful of calls proving the system is alive.
  7. Pick regression APIs — everything that needs full coverage.
  8. Exclude what isn't ready — unstable, deprecated or third-party calls.
  9. Map UI actions to APIs — open DevTools → Network, click through the app, note each call.
  10. List API-only validations — rules the UI hides (limits, rounding, permissions).
  11. Record ownership — which team or service owns each API and its data.
  12. Write it down as a scope document and a coverage matrix.

Worked example: a coverage matrix for Fake Store

Endpoint Module Auth Depends on Criticality Smoke Regression
GET /products Products Public — High ✅ ✅
GET /products/{id} Products Public — High ✅ ✅
GET /products/category/{name} Products Public — Medium   ✅
POST /auth/login Auth Public A user High ✅ ✅
POST /carts Carts Token Login, products High ✅ ✅
PUT /carts/{id} Carts Token A cart Medium   ✅
DELETE /carts/{id} Carts Token A cart Medium   ✅

The matrix answers the questions a lead will ask — what's covered, what's missing, what runs on every build — and becomes the checklist for later sprints. Plan the positive, negative and edge cases for each endpoint in the API Testing Scenario Lab.

Sprint 1 — Framework Setup

Exercises

  1. Create a Maven project for API tests.
  2. Define the folder structure.
  3. Add dependencies: REST Assured, TestNG, a JSON library, schema validation, logging.
  4. Externalise the base URI per environment.
  5. Create a BaseTest with a shared request specification.
  6. Enable logging for failed requests only.
  7. Keep secrets out of code and Git.
  8. Run one test from the command line and from CI.
  9. Push to Git with a README describing how to run it.

1. Structure

fakestore-api-tests/
├── pom.xml
├── README.md
└── src/test/
    ├── java/com/fakestore/
    │   ├── base/      BaseTest.java
    │   ├── config/    ConfigReader.java
    │   ├── services/  ProductService.java, AuthService.java, CartService.java
    │   └── tests/     SmokeTest.java
    └── resources/
        ├── config/qa.properties
        ├── schemas/product.json
        └── testng.xml

2. pom.xml dependencies

<properties>
  <maven.compiler.release>17</maven.compiler.release>
</properties>

<dependencies>
  <dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>rest-assured</artifactId>
    <version>6.0.1</version>
    <scope>test</scope>
  </dependency>

  <dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>json-schema-validator</artifactId>
    <version>6.0.1</version>
    <scope>test</scope>
  </dependency>

  <dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>7.11.0</version>
    <scope>test</scope>
  </dependency>

  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.19.2</version>
    <scope>test</scope>
  </dependency>
</dependencies>

Versions: REST Assured 6.x needs Java 17+ and brings Groovy 5 and Hamcrest with it — don't add Groovy or JsonPath separately. On Java 8 or 11, use REST Assured 5.5.7 instead (and still don't add Groovy yourself; mixing Groovy versions causes class-loading errors). Always check Maven Central for the latest patch release. Jackson (for POJOs) is optional — REST Assured also supports Gson and, from 6.0, Jackson 3.

3. Configuration per environment

# src/test/resources/config/qa.properties
baseUri=https://fakestoreapi.com
apiUser=mor_2314
public final class ConfigReader {
    private static final Properties PROPS = new Properties();

    static {
        String env = System.getProperty("env", "qa");

        try (InputStream in =
                 ConfigReader.class.getResourceAsStream(
                     "/config/" + env + ".properties")) {

            if (in == null) {
                throw new IllegalStateException("No config for env: " + env);
            }

            PROPS.load(in);

        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    public static String get(String key) {
        return System.getProperty(
            key,
            PROPS.getProperty(key)
        );
    }
}

mvn test -Denv=staging switches environments; any key can be overridden with -DbaseUri=…. Passwords come from environment variables or the CI credential store — never from a committed file.

4. BaseTest with a shared specification

public abstract class BaseTest {
    protected static RequestSpecification spec;

    @BeforeSuite(alwaysRun = true)
    public void setUpSpec() {
        RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();

        spec = new RequestSpecBuilder()
                .setBaseUri(ConfigReader.get("baseUri"))
                .setContentType(ContentType.JSON)
                .setAccept(ContentType.JSON)
                .build();
    }
}

5. A service layer

public class ProductService {

    public static Response getAll() {
        return given()
                .spec(BaseTest.spec)
                .get("/products");
    }

    public static Response getById(int id) {
        return given()
                .spec(BaseTest.spec)
                .pathParam("id", id)
                .get("/products/{id}");
    }
}

Tests call ProductService.getById(1) instead of repeating request code — the same idea as page objects in UI automation. Full layer design: REST Assured Framework Design.

Sprint 1 — The First Smoke Suite

public class SmokeTest extends BaseTest {

    @Test(groups = "smoke")
    public void productListIsAvailable() {
        List<Float> prices = ProductService.getAll()
            .then()
            .statusCode(200)
            .body("size()", greaterThan(0))
            .extract()
            .jsonPath()
            .getList("price", Float.class);

        Assert.assertTrue(
            prices.stream().allMatch(p -> p > 0),
            "every price should be positive"
        );
    }

    @Test(groups = "smoke")
    public void productDetailMatchesContract() {
        ProductService.getById(1)
            .then()
            .statusCode(200)
            .body("id", equalTo(1))
            .body(
                matchesJsonSchemaInClasspath(
                    "schemas/product.json"
                )
            );
    }

    @Test(groups = "smoke")
    public void loginReturnsToken() {
        given()
            .spec(spec)
            .body(Map.of(
                "username", ConfigReader.get("apiUser"),
                "password", System.getenv("FAKESTORE_PASSWORD")
            ))
        .when()
            .post("/auth/login")
        .then()
            .statusCode(anyOf(is(200), is(201)))
            .body("token", not(emptyOrNullString()));
    }

    @Test(groups = "smoke")
    public void cartCanBeCreatedAndDeleted() {
        int cartId = given()
                .spec(spec)
                .body(Map.of(
                    "userId", 1,
                    "products",
                    List.of(
                        Map.of(
                            "id", 1,
                            "quantity", 2
                        )
                    )
                ))
            .when()
                .post("/carts")
            .then()
                .statusCode(anyOf(is(200), is(201)))
                .extract()
                .path("id");

        given()
            .spec(spec)
            .pathParam("id", cartId)
        .when()
            .delete("/carts/{id}")
        .then()
            .statusCode(200);
    }
}

Run it with mvn test -Dgroups=smoke.

Fake Store's test credentials are listed in its documentation; set them as an environment variable rather than in the code. Fake Store simulates writes (a created cart isn't stored), so the delete checks the response code only — on your own API, follow a delete with a GET that expects 404. Its POST responses may return 200 or 201, hence the anyOf; on your project, assert the single documented code.

See how each smoke call moves through given(), when() and then() in the REST Assured Visualizer.

Wrap-up exercises

  • Add the smoke group to a Jenkins or GitHub Actions job that runs on every build — see API Testing in CI/CD.
  • Write a README: prerequisites, how to run each suite, how to switch environments, where reports appear.
  • Push to Git with a .gitignore for target/ and local config files.

From Real Projects

My API testing experience covers CRUD operations, HTTP methods, JSON path, and validating JSON and XML data. On Testsigma, a platform that itself automates API tests, understanding requests, responses and status codes was part of understanding the product. Whatever tool you use, validate the status code, the response structure and the values — not just that the call returned something. Mocks let you test error paths that the real service can't easily produce. You may also find Practice REST Assured CI/CD, Contract & Senior Tasks useful.

📚 Official documentation: GraphQL: Learn · WireMock documentation

FAQs

What should you do before automating any API?

List and group the endpoints, mark auth and dependencies, rank criticality, choose smoke and regression candidates, and record it all in a coverage matrix.

How do you choose smoke APIs?

A few calls that prove the system is alive and the core journey works — login, key reads, one create — fast enough to run on every build.

Which REST Assured version should I use?

6.x on Java 17 or later; 5.5.x on Java 8 or 11. Don't add Groovy or JsonPath dependencies yourself.

Why externalise the base URI?

So the same suite runs against QA, staging or any other environment with a command-line switch instead of code changes.

What goes in the BaseTest?

Shared setup: a request specification with base URI and headers, logging on failure, and authentication if most tests need it. A closely related topic: REST Assured Practice.