Endpoint classes are the heart of the framework. One class per API resource. Each method represents one API operation. Tests never see REST Assured directly — they call endpoint methods. This is the most important abstraction in the framework.
package com.company.api.endpoints;
import com.company.api.base.BaseEndpoint;
import com.company.api.pojo.request.CreateUserRequest;
import com.company.api.pojo.response.UserResponse;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
import static io.restassured.RestAssured.given;
public class UserEndpoint extends BaseEndpoint {
private static final String USERS = "/users";
private static final String USER_BY_ID = "/users/{id}";
public UserEndpoint(RequestSpecification spec) {
super(spec);
}
// GET /users
public Response getAllUsers() {
return doGet(USERS);
}
// GET /users?status=active
public Response getUsersByStatus(String status) {
return given()
.spec(spec)
.queryParam("status", status)
.when()
.get(USERS);
}
// GET /users/{id}
public Response getUserById(int id) {
return given()
.spec(spec)
.pathParam("id", id)
.when()
.get(USER_BY_ID);
}
// POST /users
public Response createUser(CreateUserRequest request) {
return doPost(USERS, request);
}
// PUT /users/{id}
public Response updateUser(int id, CreateUserRequest request) {
return given()
.spec(spec)
.pathParam("id", id)
.body(request)
.when()
.put(USER_BY_ID);
}
// DELETE /users/{id}
public Response deleteUser(int id) {
return given()
.spec(spec)
.pathParam("id", id)
.when()
.delete(USER_BY_ID);
}
// Helper — create and return deserialized response
public UserResponse createUserAndGet(CreateUserRequest request) {
return createUser(request)
.then()
.statusCode(201)
.extract()
.as(UserResponse.class);
}
}package com.company.api.endpoints;
import com.company.api.base.BaseEndpoint;
import com.company.api.pojo.request.CreateAccountRequest;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
import static io.restassured.RestAssured.given;
public class AccountEndpoint extends BaseEndpoint {
private static final String ACCOUNTS = "/accounts";
private static final String ACCOUNT_BY_ID = "/accounts/{id}";
private static final String ACCOUNT_TRANSACTIONS = "/accounts/{id}/transactions";
public AccountEndpoint(RequestSpecification spec) {
super(spec);
}
public Response getAllAccounts() {
return doGet(ACCOUNTS);
}
public Response getAccountById(String id) {
return given()
.spec(spec)
.pathParam("id", id)
.when()
.get(ACCOUNT_BY_ID);
}
public Response createAccount(CreateAccountRequest request) {
return doPost(ACCOUNTS, request);
}
public Response getTransactions(String accountId) {
return given()
.spec(spec)
.pathParam("id", accountId)
.when()
.get(ACCOUNT_TRANSACTIONS);
}
public Response getTransactions(String accountId,
String fromDate, String toDate) {
return given()
.spec(spec)
.pathParam("id", accountId)
.queryParam("from", fromDate)
.queryParam("to", toDate)
.when()
.get(ACCOUNT_TRANSACTIONS);
}
}Return raw Response from endpoint methods, not deserialized POJOs. Why? Because different tests need different things from the same response. One test checks status code 201. Another checks response body. A third checks headers. If you deserialize inside the endpoint, you lose flexibility.
Notice the getTransactions method is overloaded — one version takes just accountId, another takes date filters. This is how you handle optional query parameters cleanly. Each combination gets its own method signature.
Do not put assertions inside endpoint classes. An endpoint is a messenger — it delivers the response. The test decides whether the response is correct. If you put .statusCode(200) inside the endpoint, you cannot test negative scenarios like "what happens when I send invalid data?"
Q: How are your endpoint classes structured?
A: We have one endpoint class per API resource — UserEndpoint for /users, AccountEndpoint for /accounts. Each extends BaseEndpoint which provides the RequestSpec and common HTTP methods. Path strings are stored as static final constants. Each public method represents one API operation and returns a raw Response object. We use POJOs for request bodies. Methods are overloaded for optional query parameters. We do not put assertions in endpoints — the test layer decides what to assert. This separation means the same endpoint method can be used for both positive and negative test scenarios.
Key Point: One endpoint class per API resource. Methods return raw Response. Paths are constants. No assertions in endpoints — that is the test layer's job.