Q14 of 40 · REST Assured

How would you write a generic helper that accepts a path and returns a typed response?

REST AssuredMidrest-assuredgenericstyperefapi-clientdesign-pattern

Short answer

Short answer: Define a method that accepts a String path and a TypeRef<T> and calls extract().as(typeRef). The caller passes new TypeRef<User>(){} or new TypeRef<List<Order>>(){} at the call site — Jackson resolves the type token at runtime. This eliminates unchecked casts and gives compile-time safety on the return type.

Detail

A typed helper wraps the REST Assured chain so callers work with typed objects rather than raw responses:

public <T> T get(String path, TypeRef<T> type) {
    return given(reqSpec)
        .when().get(path)
        .then().statusCode(200)
        .extract().as(type);
}

Callers:

User user       = apiClient.get("/users/1", new TypeRef<User>() {});
List<User> list = apiClient.get("/users",   new TypeRef<List<User>>() {});

Extending the pattern — accept expected status code too:

public <T> T request(Method method, String path, Object body,
                     int expectedStatus, TypeRef<T> type) {
    return given(reqSpec)
        .body(body)
        .when().request(method, path)
        .then().statusCode(expectedStatus)
        .extract().as(type);
}

This service-layer pattern hides REST Assured behind an interface — if you ever swap the HTTP library, only this class changes.

// EXAMPLE

ApiClient.java

public class ApiClient {
    private final RequestSpecification spec;

    public ApiClient(RequestSpecification spec) { this.spec = spec; }

    public <T> T get(String path, TypeRef<T> type) {
        return given(spec)
            .when().get(path)
            .then().statusCode(200)
            .extract().as(type);
    }

    public <T> T post(String path, Object body, int expectedStatus, TypeRef<T> type) {
        return given(spec)
            .body(body)
            .when().post(path)
            .then().statusCode(expectedStatus)
            .extract().as(type);
    }
}

// Usage in test
User created = client.post("/users",
    Map.of("name", "Alice", "email", "alice@example.com"),
    201, new TypeRef<User>() {});
assertThat(created.getId()).isPositive();

// WHAT INTERVIEWERS LOOK FOR

Use of TypeRef (not raw Class<T>) to preserve generic type information, and the service-layer abstraction that hides REST Assured behind an API. This is a mid-to-senior pattern that shows awareness of maintainability beyond individual tests.

// COMMON PITFALL

Using Class<T> instead of TypeRef<T> — this works for non-generic types (User.class) but fails at runtime for List<User> because type erasure makes the element type unknown to Jackson.