Rest Assured Basics
Setup, GET/POST requests, JSON parsing
What is Rest Assured?
Rest Assured is a Java-based library that simplifies testing and validating REST APIs. It provides a domain-specific language (DSL) for writing powerful, readable tests.
Understanding REST APIs
REST (Representational State Transfer) APIs communicate using HTTP methods:
| Method | Purpose | Example |
|---|---|---|
GET | Retrieve data | Get user details |
POST | Create new resource | Create new user |
PUT | Update entire resource | Update user profile |
PATCH | Partial update | Update user email only |
DELETE | Remove resource | Delete user account |
Project Setup
Maven Dependencies
Add these dependencies to your pom.xml:
<dependencies>
<!-- Rest Assured -->
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<!-- JSON Schema Validation -->
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>json-schema-validator</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<!-- TestNG -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.9.0</version>
<scope>test</scope>
</dependency>
<!-- Jackson for JSON serialization -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.0</version>
</dependency>
</dependencies>
Static Imports
Add these imports to use Rest Assured’s fluent API:
import static io.restassured.RestAssured.*;
import static io.restassured.matcher.RestAssuredMatchers.*;
import static org.hamcrest.Matchers.*;
Your First GET Request
Basic GET Request
The simplest way to make a GET request:
@Test
public void getListOfUsers() {
given()
.baseUri("https://reqres.in")
.when()
.get("/api/users?page=2")
.then()
.statusCode(200)
.body("page", equalTo(2))
.body("data.size()", greaterThan(0));
}
Understanding the BDD Pattern
GET with Path Parameters
@Test
public void getSingleUser() {
int userId = 2;
given()
.baseUri("https://reqres.in")
.pathParam("id", userId)
.when()
.get("/api/users/{id}")
.then()
.statusCode(200)
.body("data.id", equalTo(userId))
.body("data.email", containsString("@"));
}
GET with Query Parameters
@Test
public void getUsersWithQueryParams() {
given()
.baseUri("https://reqres.in")
.queryParam("page", 1)
.queryParam("per_page", 5)
.when()
.get("/api/users")
.then()
.statusCode(200)
.body("per_page", equalTo(5))
.body("data", hasSize(lessThanOrEqualTo(5)));
}
Extracting Response Data
@Test
public void extractResponseData() {
Response response = given()
.baseUri("https://reqres.in")
.when()
.get("/api/users/2")
.then()
.extract().response();
// Extract specific values
String email = response.jsonPath().getString("data.email");
int id = response.jsonPath().getInt("data.id");
String firstName = response.path("data.first_name");
System.out.println("User: " + firstName + " (" + email + ")");
// Get entire response as String
String responseBody = response.asString();
// Get status code
int statusCode = response.getStatusCode();
}
POST Request with JSON
POST with JSON String
@Test
public void createUserWithJsonString() {
String requestBody = """
{
"name": "John Doe",
"job": "QA Engineer"
}
""";
given()
.baseUri("https://reqres.in")
.contentType(ContentType.JSON)
.body(requestBody)
.when()
.post("/api/users")
.then()
.statusCode(201)
.body("name", equalTo("John Doe"))
.body("job", equalTo("QA Engineer"))
.body("id", notNullValue())
.body("createdAt", notNullValue());
}
POST with HashMap
@Test
public void createUserWithMap() {
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("name", "Jane Smith");
requestBody.put("job", "Developer");
given()
.baseUri("https://reqres.in")
.contentType(ContentType.JSON)
.body(requestBody)
.when()
.post("/api/users")
.then()
.statusCode(201)
.body("name", equalTo("Jane Smith"));
}
POST with POJO (Recommended)
Create a model class for cleaner, type-safe code:
// User.java - POJO class
public class User {
private String name;
private String job;
public User() {}
public User(String name, String job) {
this.name = name;
this.job = job;
}
// Getters and Setters
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getJob() { return job; }
public void setJob(String job) { this.job = job; }
}
@Test
public void createUserWithPojo() {
User user = new User("Alex Brown", "Automation Lead");
given()
.baseUri("https://reqres.in")
.contentType(ContentType.JSON)
.body(user) // Automatically serialized to JSON
.when()
.post("/api/users")
.then()
.statusCode(201)
.body("name", equalTo("Alex Brown"));
}
Deserialize Response to POJO
@Test
public void deserializeResponse() {
User createdUser = given()
.baseUri("https://reqres.in")
.contentType(ContentType.JSON)
.body(new User("Test User", "Tester"))
.when()
.post("/api/users")
.then()
.statusCode(201)
.extract()
.as(User.class); // Deserialize to POJO
Assert.assertEquals(createdUser.getName(), "Test User");
}
Response Validation
Status Code Validation
@Test
public void validateStatusCodes() {
// Exact match
given().get("https://reqres.in/api/users/2")
.then().statusCode(200);
// Using Hamcrest matchers
given().get("https://reqres.in/api/users/2")
.then().statusCode(is(200));
// Range check
given().get("https://reqres.in/api/users/2")
.then().statusCode(both(greaterThanOrEqualTo(200))
.and(lessThan(300)));
}
Header Validation
@Test
public void validateHeaders() {
given()
.baseUri("https://reqres.in")
.when()
.get("/api/users")
.then()
.header("Content-Type", containsString("application/json"))
.header("Connection", equalTo("keep-alive"));
}
JSON Body Validation with JsonPath
@Test
public void validateJsonBody() {
given()
.baseUri("https://reqres.in")
.when()
.get("/api/users/2")
.then()
.statusCode(200)
// Simple field validation
.body("data.id", equalTo(2))
.body("data.email", endsWith("@reqres.in"))
.body("data.first_name", not(emptyString()))
// Nested object validation
.body("support.url", containsString("reqres"))
// Check field exists
.body("data", hasKey("avatar"));
}
Array Validation
@Test
public void validateArrayResponse() {
given()
.baseUri("https://reqres.in")
.when()
.get("/api/users?page=1")
.then()
.statusCode(200)
// Array size
.body("data.size()", greaterThan(0))
.body("data", hasSize(6))
// All items match condition
.body("data.id", everyItem(greaterThan(0)))
.body("data.email", everyItem(containsString("@")))
// Check specific item
.body("data[0].id", equalTo(1))
// Find item in array
.body("data.find { it.id == 1 }.email", notNullValue());
}
Response Time Validation
@Test
public void validateResponseTime() {
given()
.baseUri("https://reqres.in")
.when()
.get("/api/users")
.then()
.time(lessThan(2000L)); // Response time
Logging & Debugging
Request and Response Logging
@Test
public void loggingExample() {
given()
.baseUri("https://reqres.in")
.log().all() // Log entire request
.when()
.get("/api/users/2")
.then()
.log().all() // Log entire response
.statusCode(200);
}
Selective Logging
@Test
public void selectiveLogging() {
given()
.baseUri("https://reqres.in")
.log().uri() // Log only URI
.log().method() // Log HTTP method
.log().headers() // Log headers
.when()
.get("/api/users/2")
.then()
.log().status() // Log status line
.log().body() // Log response body
.statusCode(200);
}
Log on Failure Only
@Test
public void logOnlyOnFailure() {
given()
.baseUri("https://reqres.in")
.log().ifValidationFails() // Log request if validation fails
.when()
.get("/api/users/2")
.then()
.log().ifValidationFails() // Log response if validation fails
.statusCode(200);
}
Global Configuration
Setting Base URI and Path
public class BaseTest {
@BeforeClass
public void setup() {
// Set base URI for all requests
RestAssured.baseURI = "https://reqres.in";
RestAssured.basePath = "/api";
// Default content type
RestAssured.requestSpecification = given()
.contentType(ContentType.JSON)
.accept(ContentType.JSON);
}
@AfterClass
public void teardown() {
RestAssured.reset(); // Reset to defaults
}
}
Request Specification
Create reusable request specifications:
public class ApiSpecs {
public static RequestSpecification getDefaultSpec() {
return new RequestSpecBuilder()
.setBaseUri("https://reqres.in")
.setBasePath("/api")
.setContentType(ContentType.JSON)
.addHeader("Accept", "application/json")
.log(LogDetail.ALL)
.build();
}
}
// Usage in tests
@Test
public void testWithSpec() {
given()
.spec(ApiSpecs.getDefaultSpec())
.when()
.get("/users/2")
.then()
.statusCode(200);
}
Response Specification
public static ResponseSpecification getSuccessSpec() {
return new ResponseSpecBuilder()
.expectStatusCode(200)
.expectContentType(ContentType.JSON)
.expectResponseTime(lessThan(3000L))
.build();
}
// Usage
@Test
public void testWithResponseSpec() {
given()
.spec(ApiSpecs.getDefaultSpec())
.when()
.get("/users/2")
.then()
.spec(getSuccessSpec())
.body("data.id", equalTo(2));
}
Best Practices
Complete Test Example
public class UserApiTest {
private static RequestSpecification requestSpec;
@BeforeClass
public static void setup() {
requestSpec = new RequestSpecBuilder()
.setBaseUri("https://reqres.in")
.setBasePath("/api")
.setContentType(ContentType.JSON)
.log(LogDetail.URI)
.build();
}
@Test
public void testCreateAndVerifyUser() {
// Create user
User newUser = new User("Integration Test", "SDET");
String userId = given()
.spec(requestSpec)
.body(newUser)
.when()
.post("/users")
.then()
.statusCode(201)
.body("name", equalTo(newUser.getName()))
.extract()
.path("id");
Assert.assertNotNull(userId, "User ID should not be null");
}
@Test
public void testGetNonExistentUser() {
given()
.spec(requestSpec)
.when()
.get("/users/999")
.then()
.statusCode(404);
}
}