You are writing 20 test methods. Every single one starts with contentType(JSON), header("Authorization", "Bearer token"), baseUri("https://api.myapp.com"). Copy-paste everywhere. Now the token changes. You update 20 methods. This is the problem RequestSpecBuilder solves.
Think of specs like templates. You define the common setup once, and every test uses it. Like creating a letterhead — you do not type the company address on every letter.
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
public class PostsApiTest {
private RequestSpecification requestSpec;
@BeforeClass
public void setup() {
requestSpec = new RequestSpecBuilder()
.setBaseUri("https://jsonplaceholder.typicode.com")
.setContentType(ContentType.JSON)
.addHeader("Accept", "application/json")
.addHeader("X-App-Version", "2.1")
.log(LogDetail.URI) // Log URL for every request
.build();
}
@Test
public void testGetPosts() {
given()
.spec(requestSpec) // Apply the template
.when()
.get("/posts")
.then()
.statusCode(200);
}
@Test
public void testGetUsers() {
given()
.spec(requestSpec) // Same template, different endpoint
.when()
.get("/users")
.then()
.statusCode(200);
}
}Same idea, but for responses. Every successful GET should return 200, have Content-Type JSON, and respond within 3 seconds. Define it once.
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.specification.ResponseSpecification;
public class SpecsTest {
private RequestSpecification requestSpec;
private ResponseSpecification responseSpec200;
private ResponseSpecification responseSpec201;
@BeforeClass
public void setup() {
requestSpec = new RequestSpecBuilder()
.setBaseUri("https://jsonplaceholder.typicode.com")
.setContentType(ContentType.JSON)
.build();
// For successful GET responses
responseSpec200 = new ResponseSpecBuilder()
.expectStatusCode(200)
.expectContentType(ContentType.JSON)
.expectResponseTime(lessThan(5000L)) // Under 5 seconds
.build();
// For successful POST responses
responseSpec201 = new ResponseSpecBuilder()
.expectStatusCode(201)
.expectContentType(ContentType.JSON)
.build();
}
@Test
public void testGetPosts() {
given()
.spec(requestSpec)
.when()
.get("/posts")
.then()
.spec(responseSpec200) // Apply response template
.body("size()", equalTo(100));
}
@Test
public void testCreatePost() {
given()
.spec(requestSpec)
.body(Map.of("title", "New Post", "body", "Content", "userId", 1))
.when()
.post("/posts")
.then()
.spec(responseSpec201); // Different response template
}
}In real frameworks, you put specs in a base class. All test classes extend it. This is the foundation of a scalable API test framework.
// base/BaseTest.java
public class BaseTest {
protected RequestSpecification requestSpec;
protected ResponseSpecification responseSpec200;
@BeforeClass
public void baseSetup() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
requestSpec = new RequestSpecBuilder()
.setContentType(ContentType.JSON)
.addHeader("Accept", "application/json")
.build();
responseSpec200 = new ResponseSpecBuilder()
.expectStatusCode(200)
.expectContentType(ContentType.JSON)
.build();
}
}
// tests/PostsTest.java — inherits everything
public class PostsTest extends BaseTest {
@Test
public void testGetAllPosts() {
given()
.spec(requestSpec)
.when()
.get("/posts")
.then()
.spec(responseSpec200)
.body("size()", equalTo(100));
}
}You can add more assertions on top of a response spec. The spec is a baseline. If a specific test needs extra checks, just chain them after .spec(responseSpec). Specs do not limit you — they save you from repeating the basics.
Q: What are RequestSpecBuilder and ResponseSpecBuilder? Why use them?
A: RequestSpecBuilder creates a reusable request template with common settings — base URI, content type, headers, auth tokens. ResponseSpecBuilder creates a reusable response validation template — expected status code, content type, response time. You define them once in @BeforeClass and use .spec(requestSpec) / .spec(responseSpec) in every test. This eliminates code duplication. When something changes (like a header value), you update one line instead of 50 tests. In real frameworks, specs live in a BaseTest class that all test classes extend.
Key Point: RequestSpecBuilder templates your request setup. ResponseSpecBuilder templates your response validation. Put them in a BaseTest class. All test classes extend BaseTest. Change once, apply everywhere.