Java DSL for easy testing of REST services
—
Extensible filter system for request/response processing, logging, timing, session management, and custom behavior injection to enhance REST Assured functionality.
Base interface for creating custom filters that can intercept and modify requests and responses.
/**
* Base interface for REST Assured filters
*/
interface Filter {
/**
* Filter method called for each request/response cycle
* @param requestSpec Filterable request specification
* @param responseSpec Filterable response specification
* @param ctx Filter context for continuing the filter chain
* @return The response after filtering
*/
Response filter(FilterableRequestSpecification requestSpec,
FilterableResponseSpecification responseSpec,
FilterContext ctx);
}
/**
* Ordered filter interface with execution priority
*/
interface OrderedFilter extends Filter {
/**
* Get the order/priority of this filter (lower values execute first)
* @return Filter execution order
*/
int getOrder();
}
/**
* Filter context for continuing the filter chain
*/
interface FilterContext {
/**
* Continue with the next filter in the chain
* @param requestSpec Updated request specification
* @param responseSpec Updated response specification
* @return Response from the filter chain
*/
Response next(FilterableRequestSpecification requestSpec,
FilterableResponseSpecification responseSpec);
}Usage Examples:
// Custom filter implementation
public class TimingFilter implements Filter {
@Override
public Response filter(FilterableRequestSpecification requestSpec,
FilterableResponseSpecification responseSpec,
FilterContext ctx) {
long startTime = System.currentTimeMillis();
Response response = ctx.next(requestSpec, responseSpec);
long duration = System.currentTimeMillis() - startTime;
System.out.println("Request took: " + duration + "ms");
return response;
}
}
// Using custom filter
given()
.filter(new TimingFilter())
.when()
.get("/users")
.then()
.statusCode(200);
// Global filter
RestAssured.filters(new TimingFilter());Filters for logging HTTP request details.
/**
* Filter for logging HTTP requests
*/
class RequestLoggingFilter implements Filter {
/**
* Create request logging filter with default settings
*/
RequestLoggingFilter();
/**
* Create request logging filter with specific log detail
* @param logDetail Level of detail to log
*/
RequestLoggingFilter(LogDetail logDetail);
/**
* Create request logging filter with custom print stream
* @param printStream Stream to write log output to
*/
RequestLoggingFilter(PrintStream printStream);
/**
* Create request logging filter with detail and stream
* @param logDetail Level of detail to log
* @param printStream Stream to write log output to
*/
RequestLoggingFilter(LogDetail logDetail, PrintStream printStream);
/**
* Log request if status code matches predicate
* @param shouldLog Predicate to determine if request should be logged
* @return Request logging filter
*/
static RequestLoggingFilter logRequestTo(PrintStream printStream);
/**
* Log request if status code matches
* @param statusCode Status code to match for logging
* @return Request logging filter
*/
static RequestLoggingFilter logRequestIfStatusCodeIs(int statusCode);
/**
* Log request if status code matches any of the provided codes
* @param statusCodes Status codes to match for logging
* @return Request logging filter
*/
static RequestLoggingFilter logRequestIfStatusCodeMatches(Matcher<Integer> statusCodes);
}Usage Examples:
// Basic request logging
given()
.filter(new RequestLoggingFilter())
.when()
.get("/users");
// Log only headers and parameters
given()
.filter(new RequestLoggingFilter(LogDetail.HEADERS))
.when()
.post("/users");
// Conditional request logging
given()
.filter(RequestLoggingFilter.logRequestIfStatusCodeIs(500))
.when()
.get("/users");
// Log to custom stream
given()
.filter(new RequestLoggingFilter(System.err))
.when()
.get("/users");Filters for logging HTTP response details.
/**
* Filter for logging HTTP responses
*/
class ResponseLoggingFilter implements Filter {
/**
* Create response logging filter with default settings
*/
ResponseLoggingFilter();
/**
* Create response logging filter with specific log detail
* @param logDetail Level of detail to log
*/
ResponseLoggingFilter(LogDetail logDetail);
/**
* Create response logging filter with custom print stream
* @param printStream Stream to write log output to
*/
ResponseLoggingFilter(PrintStream printStream);
/**
* Create response logging filter with detail and stream
* @param logDetail Level of detail to log
* @param printStream Stream to write log output to
*/
ResponseLoggingFilter(LogDetail logDetail, PrintStream printStream);
/**
* Log response to specific print stream
* @param printStream Stream to write log output to
* @return Response logging filter
*/
static ResponseLoggingFilter logResponseTo(PrintStream printStream);
/**
* Log response if status code matches
* @param statusCode Status code to match for logging
* @return Response logging filter
*/
static ResponseLoggingFilter logResponseIfStatusCodeIs(int statusCode);
/**
* Log response if status code matches predicate
* @param statusCodes Status code matcher for logging
* @return Response logging filter
*/
static ResponseLoggingFilter logResponseIfStatus CodeMatches(Matcher<Integer> statusCodes);
/**
* Log response body if content type matches
* @param contentType Content type to match for logging
* @return Response logging filter
*/
static ResponseLoggingFilter logResponseIfContentTypeMatches(String contentType);
}Filter for logging only error responses.
/**
* Filter for logging error responses (4xx and 5xx status codes)
*/
class ErrorLoggingFilter implements Filter {
/**
* Create error logging filter with default settings
*/
ErrorLoggingFilter();
/**
* Create error logging filter with custom print stream
* @param printStream Stream to write error logs to
*/
ErrorLoggingFilter(PrintStream printStream);
/**
* Create error logging filter with specific log detail
* @param logDetail Level of detail to log for errors
*/
ErrorLoggingFilter(LogDetail logDetail);
/**
* Create error logging filter with detail and stream
* @param logDetail Level of detail to log
* @param printStream Stream to write error logs to
*/
ErrorLoggingFilter(LogDetail logDetail, PrintStream printStream);
/**
* Log errors to specific print stream
* @param printStream Stream to write error logs to
* @return Error logging filter
*/
static ErrorLoggingFilter logErrorsTo(PrintStream printStream);
}Filters for handling session cookies and session-based authentication.
/**
* Filter for automatic session management via cookies
*/
class SessionFilter implements Filter {
/**
* Create session filter with default session ID cookie name
*/
SessionFilter();
/**
* Create session filter with custom session ID cookie name
* @param sessionIdName Name of the session ID cookie
*/
SessionFilter(String sessionIdName);
/**
* Get the current session ID
* @return Current session ID value
*/
String getSessionId();
/**
* Set the session ID
* @param sessionId Session ID to set
*/
void setSessionId(String sessionId);
}Usage Examples:
// Automatic session management
SessionFilter sessionFilter = new SessionFilter();
// Login to get session
given()
.filter(sessionFilter)
.formParam("username", "user")
.formParam("password", "password")
.when()
.post("/login")
.then()
.statusCode(200);
// Use session for subsequent requests
given()
.filter(sessionFilter) // Automatically includes session cookie
.when()
.get("/protected")
.then()
.statusCode(200);
// Custom session cookie name
SessionFilter customSessionFilter = new SessionFilter("CUSTOM_SESSION_ID");Filter for persistent cookie management across requests.
/**
* Filter for managing cookies across multiple requests
*/
class CookieFilter implements Filter {
/**
* Create cookie filter
*/
CookieFilter();
/**
* Get all managed cookies
* @return Cookies object containing all cookies
*/
Cookies getCookies();
/**
* Get specific cookie value
* @param cookieName Name of the cookie
* @return Cookie value or null if not found
*/
String getCookieValue(String cookieName);
}Filters for measuring request/response timing and performance.
/**
* Filter for measuring request timing
*/
class TimingFilter implements Filter {
/**
* Create timing filter
*/
TimingFilter();
/**
* Get the last request duration in milliseconds
* @return Duration of last request in milliseconds
*/
long getTimeIn(TimeUnit timeUnit);
/**
* Get validation result including timing information
* @return Validation result with timing data
*/
ValidatableResponse and();
/**
* Validate response time
* @param matcher Matcher for response time validation
* @param timeUnit Time unit for the matcher
* @return Validatable response for chaining
*/
ValidatableResponse time(Matcher<Long> matcher, TimeUnit timeUnit);
}Usage Examples:
// Timing filter usage
TimingFilter timingFilter = new TimingFilter();
Response response = given()
.filter(timingFilter)
.when()
.get("/users")
.then()
.statusCode(200)
.time(lessThan(2000L), TimeUnit.MILLISECONDS)
.extract()
.response();
long duration = timingFilter.getTimeIn(TimeUnit.MILLISECONDS);
System.out.println("Request took: " + duration + "ms");Methods for configuring filters at request and global levels.
// Request-level filter configuration
interface RequestSpecification {
/**
* Add a filter to this request
* @param filter Filter to add
* @return Updated request specification
*/
RequestSpecification filter(Filter filter);
/**
* Add multiple filters to this request
* @param filters List of filters to add
* @return Updated request specification
*/
RequestSpecification filters(List<Filter> filters);
/**
* Add filters to this request
* @param filter First filter to add
* @param additionalFilters Additional filters to add
* @return Updated request specification
*/
RequestSpecification filters(Filter filter, Filter... additionalFilters);
}
// Global filter configuration (static methods in RestAssured)
/**
* Add filters to be applied to all requests
* @param filters List of filters to add globally
*/
static void filters(List<Filter> filters);
/**
* Add filters to be applied to all requests
* @param filter First filter to add globally
* @param additionalFilters Additional filters to add globally
*/
static void filters(Filter filter, Filter... additionalFilters);
/**
* Replace all existing global filters with new filters
* @param filters List of filters to set as global filters
*/
static void replaceFiltersWith(List<Filter> filters);
/**
* Replace all existing global filters with new filters
* @param filter First filter to set
* @param additionalFilters Additional filters to set
*/
static void replaceFiltersWith(Filter filter, Filter... additionalFilters);
/**
* Get current list of global filters
* @return Unmodifiable list of current global filters
*/
static List<Filter> filters();Examples of implementing custom filters for specific use cases.
Authorization Header Filter:
public class AuthorizationFilter implements Filter {
private final String token;
public AuthorizationFilter(String token) {
this.token = token;
}
@Override
public Response filter(FilterableRequestSpecification requestSpec,
FilterableResponseSpecification responseSpec,
FilterContext ctx) {
requestSpec.header("Authorization", "Bearer " + token);
return ctx.next(requestSpec, responseSpec);
}
}Request ID Filter:
public class RequestIdFilter implements Filter {
@Override
public Response filter(FilterableRequestSpecification requestSpec,
FilterableResponseSpecification responseSpec,
FilterContext ctx) {
String requestId = UUID.randomUUID().toString();
requestSpec.header("X-Request-ID", requestId);
Response response = ctx.next(requestSpec, responseSpec);
System.out.println("Request ID: " + requestId +
", Status: " + response.getStatusCode());
return response;
}
}Retry Filter:
public class RetryFilter implements Filter {
private final int maxRetries;
private final long delayMs;
public RetryFilter(int maxRetries, long delayMs) {
this.maxRetries = maxRetries;
this.delayMs = delayMs;
}
@Override
public Response filter(FilterableRequestSpecification requestSpec,
FilterableResponseSpecification responseSpec,
FilterContext ctx) {
Response response = null;
Exception lastException = null;
for (int attempt = 0; attempt <= maxRetries; attempt++) {
try {
response = ctx.next(requestSpec, responseSpec);
if (response.getStatusCode() < 500) {
return response; // Success or client error
}
} catch (Exception e) {
lastException = e;
}
if (attempt < maxRetries) {
try {
Thread.sleep(delayMs);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
if (lastException != null) {
throw new RuntimeException("Request failed after " + maxRetries + " retries", lastException);
}
return response;
}
}// Main filter interfaces
interface Filter {
Response filter(FilterableRequestSpecification requestSpec,
FilterableResponseSpecification responseSpec,
FilterContext ctx);
}
interface OrderedFilter extends Filter {
int getOrder();
}
interface FilterContext {
Response next(FilterableRequestSpecification requestSpec,
FilterableResponseSpecification responseSpec);
}
// Filterable specification interfaces
interface FilterableRequestSpecification extends RequestSpecification {
// Extends RequestSpecification with additional methods visible to filters
}
interface FilterableResponseSpecification extends ResponseSpecification {
// Extends ResponseSpecification with additional methods visible to filters
}
// Built-in filter classes
class RequestLoggingFilter implements Filter {
// Request logging implementation
}
class ResponseLoggingFilter implements Filter {
// Response logging implementation
}
class ErrorLoggingFilter implements Filter {
// Error logging implementation
}
class SessionFilter implements Filter {
// Session management implementation
}
class CookieFilter implements Filter {
// Cookie management implementation
}
class TimingFilter implements Filter {
// Timing measurement implementation
}
// Log detail enumeration
enum LogDetail {
ALL, STATUS, HEADERS, COOKIES, BODY, PARAMS, METHOD, URI
}Complete Filter Usage Example:
public class APITestWithFilters {
private static final String API_TOKEN = "your-api-token";
@Test
public void testWithMultipleFilters() {
// Setup global filters
RestAssured.filters(
new AuthorizationFilter(API_TOKEN),
new RequestIdFilter(),
ResponseLoggingFilter.logResponseIfStatusCodeIs(500)
);
// Create session filter for this test
SessionFilter sessionFilter = new SessionFilter();
// Test with additional request-specific filters
given()
.filter(sessionFilter)
.filter(new TimingFilter())
.contentType(ContentType.JSON)
.body(new User("John", "john@example.com"))
.when()
.post("/users")
.then()
.statusCode(201)
.time(lessThan(3L), TimeUnit.SECONDS)
.body("name", equalTo("John"));
// Use session filter for authenticated request
given()
.filter(sessionFilter)
.when()
.get("/users/me")
.then()
.statusCode(200);
}
}Install with Tessl CLI
npx tessl i tessl/maven-io-rest-assured--rest-assured