skip to content

Ready-Made Filters

The seven filters that ship in the box, what each one prints or remembers, and which two carry state from one request to the next. Most teams reach for these before writing their own.

part ofREST Assuredoverview, primer and where to startread it →
on this pageshow

questions

5

What filters ship with REST Assured out of the box, and how do you register one on a request?

level: juniorimportance: should knowfreq 58%

answer

  1. four packages under io.restassured.filter
  2. four print, one times, two remember
  3. given().filter(...) or RestAssured.filters(...)
  4. seven shipped implementations, no retry filter

basics

~20 s

REST Assured ships seven ready-made filters: RequestLoggingFilter, ResponseLoggingFilter, ErrorLoggingFilter, StatusCodeBasedLoggingFilter, TimingFilter, CookieFilter and SessionFilter. Four of them print, one records elapsed time, and two remember state between calls. Register one with given().filter(...), or on every call through RestAssured.filters(...).

solid answer

~50 s

REST Assured's public filter packages -- `io.restassured.filter.log`, `.cookie`, `.session` and `.time` -- hold seven implementations, and most suites never need more. Four of them print: `RequestLoggingFilter` prints the built request specification, `ResponseLoggingFilter` prints the response and can be gated by a status matcher, `ErrorLoggingFilter` prints the response when the status is 400 to 500 inclusive, and `StatusCodeBasedLoggingFilter` is the shared base the last two extend rather than something you instantiate. `TimingFilter` records elapsed milliseconds into the filter context. `CookieFilter` and `SessionFilter` are the two that carry state, and each keeps it on the filter *instance*, so the same object has to be reused. Register with `given().filter(f)`, `given().filters(...)`, `RequestSpecBuilder.addFilter(f)` or the static `RestAssured.filters(...)`; `noFilters()` and `noFiltersOfType(Class)` drop inherited ones again. None of the seven is registered by default, with one exception: REST Assured appends a `TimingFilter` itself when the chain has none.

code

java · 39 lines
java
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.filter.cookie.CookieFilter;
import io.restassured.filter.log.ErrorLoggingFilter;
import io.restassured.specification.RequestSpecification;

import static io.restassured.RestAssured.given;

public class MuseumTicketingSpec {

    // one instance, reused: the cookie store lives on the filter
    private static final CookieFilter COOKIES = new CookieFilter();

    private static final RequestSpecification SPEC = new RequestSpecBuilder()
            .setBaseUri("https://api.museum.example")
            .setBasePath("/v1")
            .addFilter(COOKIES)
            .addFilter(new ErrorLoggingFilter())
            .build();

    public void buyAndCheckIn() {
        given().spec(SPEC)
                .formParam("email", "[email protected]")
                .formParam("password", "s3cret")
                .post("/sessions")
                .then().statusCode(200);

        String ticketCode = given().spec(SPEC)
                .contentType("application/json")
                .body("{\"exhibitionId\":\"pompeii\",\"slotId\":\"2026-04-11T10:00\"}")
                .post("/tickets")
                .then().statusCode(201)
                .extract().path("ticketCode");

        given().spec(SPEC)
                .noFiltersOfType(ErrorLoggingFilter.class)
                .post("/visits/{code}/check-in", ticketCode)
                .then().statusCode(200);
    }
}

go deeper

for a junior

Be ready to name the shipped filters without notes and to show the one-line registration, given().filter(new RequestLoggingFilter()). Grouping them as four printers, one timer and two rememberers is worth more than reciting seven class names.

for a middle

Explain the mechanics: which package each filter lives in, that ErrorLoggingFilter and ResponseLoggingFilter share a base class, and that the two stateful ones keep their memory on the instance rather than on the specification.

for a senior

Show suite-wide judgment. Put logging and cookie filters on a shared request specification or the static list rather than in every test, and use noFiltersOfType(...) to keep one chatty endpoint out of the CI log.

for a principal

Own the line between what the library already ships and what your team writes. Every house-written filter is code someone maintains, and a filter registered globally runs on every request in the suite -- that cost is a design decision, not an afterthought.

A **filter** in REST Assured is the library's around-advice for one HTTP call: it sees the request specification before the call is committed and the response before your expectations run. Seven implementations ship inside the library, spread across four public packages, and between them they cover the cross-cutting jobs an API suite usually needs -- printing, timing, and carrying cookies forward. ## The seven, and what each one does | Filter | Package | What it does | | --- | --- | --- | | `RequestLoggingFilter` | `io.restassured.filter.log` | Prints the built request specification, then delegates | | `ResponseLoggingFilter` | `io.restassured.filter.log` | Prints the response, optionally gated by a status matcher | | `ErrorLoggingFilter` | `io.restassured.filter.log` | Prints the response when the status is 400 to 500 inclusive | | `StatusCodeBasedLoggingFilter` | `io.restassured.filter.log` | Shared base of the two above; not declared `public` | | `TimingFilter` | `io.restassured.filter.time` | Records elapsed milliseconds into the filter context | | `CookieFilter` | `io.restassured.filter.cookie` | Replays and stores cookies across calls | | `SessionFilter` | `io.restassured.filter.session` | Replays and stores the session identifier across calls | Three lines in that table are easy to state wrongly: - `StatusCodeBasedLoggingFilter` is declared **without** the `public` modifier. It ships, and both `ResponseLoggingFilter` and `ErrorLoggingFilter` extend it, but you cannot call its constructor from your own package -- you reach the same behaviour through `new ResponseLoggingFilter(matcher)`, which forwards to it. - `ErrorLoggingFilter`'s window is **inclusive at both ends**: `allOf(greaterThanOrEqualTo(400), lessThanOrEqualTo(500))`. A 500 triggers it; a 503 does not. - Only `CookieFilter` and `SessionFilter` remember anything between calls. The other five begin every request with a clean slate. ## Static factories, because the naming is not uniform Several of the seven carry static factory methods that read better inside a chain than a bare constructor: 1. `RequestLoggingFilter.logRequestTo(stream)` and `RequestLoggingFilter.with(LogDetail...)`. 2. `ResponseLoggingFilter.responseLogger()`, `logResponseTo(stream)`, `logResponseIfStatusCodeIs(int)` and `logResponseIfStatusCodeMatches(Matcher<Integer>)`. 3. `ErrorLoggingFilter.errorLogger()` and `ErrorLoggingFilter.logErrorsTo(stream)`. 4. `TimingFilter.measureTime()`. 5. `CookieFilter` and `SessionFilter` have none at all -- you call `new`, and you keep the reference, because the reference *is* the memory. ## Four places you can register one Take a suite against a museum ticketing API. A single call takes a filter directly, and everything wider is built from the same idea: - `given().filter(new ErrorLoggingFilter())` -- one filter, one call. - `given().filters(listOfFilters)` or `given().filters(first, second)` -- several at once. - `new RequestSpecBuilder().addFilter(f).build()` -- baked into a request specification every test reuses. - `RestAssured.filters(new ErrorLoggingFilter())` -- a static default applied to every subsequent request. `RestAssured.replaceFiltersWith(...)` swaps the whole list, and `RestAssured.reset()` empties it along with the other statics. Going the other way matters just as much in a real suite. `given().noFilters()` drops every inherited filter for one call, and `given().noFiltersOfType(ResponseLoggingFilter.class)` drops one kind -- which is what you want when `GET /v1/exhibitions/{exhibitionId}/slots` returns a large slot inventory that you do not want printed into a CI log on every run. ## Where the seven sit in the chain None of the seven implements `OrderedFilter`, so every one of them takes the default precedence of `1000`, and the sort REST Assured applies is stable. **Registration order therefore decides** among the shipped filters, and two consequences follow that bite in practice: - A `RequestLoggingFilter` registered *before* a `CookieFilter` prints its output before the cookie filter has added the stored cookies, so those cookies are absent from the log even though they are sent. - REST Assured appends its own `TimingFilter` last, immediately before the internal filter that actually sends the request, unless you have already registered one yourself. ## A worked museum-ticketing setup A suite that logs in through `POST /v1/sessions`, buys through `POST /v1/tickets` and then checks in through `POST /v1/visits/{ticketCode}/check-in` usually wants two of the seven and no more. An `ErrorLoggingFilter` on the shared specification means a failing purchase explains itself in the build output without any per-test wiring. A `CookieFilter` held as a field -- one instance, reused -- means the cookie set at login survives into the purchase and the check-in. What the shipped set deliberately does not give you is equally worth naming in an interview: - There is **no retry filter**, and no retry anywhere in REST Assured; a retry is a loop or a runner feature outside the library. - There is no correlation-id filter, no schema-check filter and no request-signing filter. - Anything on that list is a hand-written `Filter` implementation, which is a separate skill from knowing the seven that already exist. The practical summary an interviewer is listening for is short: four printers, one timer, two rememberers; register with `filter(...)` or `filters(...)`; and the two that remember must be the same instance every time.

  • Which of the seven shipped filters need you to hold on to the instance, and why?
    Only `CookieFilter` and `SessionFilter`. Their memory is instance state -- a `BasicCookieStore` and an `AtomicReference<String>` respectively -- so a `new CookieFilter()` created inside each test method starts empty and carries nothing forward. The logging filters and `TimingFilter` hold no per-request memory, so a fresh instance behaves identically to a reused one.
  • How do you turn a globally registered logging filter off for one noisy endpoint?
    Use `given().noFiltersOfType(ResponseLoggingFilter.class)` on that one call, which drops just that kind while leaving the rest of the inherited filters in place. `given().noFilters()` is the blunter form and removes all of them. Neither touches the static list, so the next request still gets whatever `RestAssured.filters(...)` set up.

saying these in an interview costs you the question

  • Claiming REST Assured ships a retry or polling filter
  • Saying ErrorLoggingFilter prints the request as well as the response
  • Creating a new CookieFilter in every test and expecting cookies to persist
  • Thinking StatusCodeBasedLoggingFilter is a class you instantiate directly
  • Assuming every shipped filter is registered by default
open as a page

In REST Assured, which status codes trigger ErrorLoggingFilter, and how does that differ from then().log().ifError()?

level: middleimportance: should knowfreq 42%

basics

~20 s

REST Assured's ErrorLoggingFilter fires only on status codes 400 through 500 inclusive, because it is built with Hamcrest allOf(greaterThanOrEqualTo(400), lessThanOrEqualTo(500)). The then().log().ifError() shortcut uses a statusCode >= 400 test instead. So a 503 prints through ifError() but never through ErrorLoggingFilter.

open as a page

Which REST Assured filters carry state between requests, and where does that state actually live?

level: middleimportance: should knowfreq 51%

basics

~20 s

Two of REST Assured's seven filters remember anything: CookieFilter and SessionFilter. Both keep their memory on the filter object, not on the request specification. So the same instance must be registered on every call, or each request starts empty.

open as a page

Why can REST Assured's RequestLoggingFilter output differ from what the server actually receives?

level: seniorimportance: should knowfreq 46%

basics

~20 s

REST Assured's RequestLoggingFilter prints the request specification, not the bytes on the wire. It prints before calling ctx.next(...), so later filters can still change the request, and the HTTP client adds headers afterwards. Treat the output as intent, not evidence.

open as a page

In REST Assured, what does TimingFilter record, and what changes when you register it yourself?

level: seniorimportance: should knowfreq 33%

basics

~20 s

REST Assured's TimingFilter records the milliseconds around its ctx.next(...) call and stores them in the filter context under RA_RESPONSE_TIME_MILLIS. The library appends one automatically at the end of the chain, so registering TimingFilter.measureTime() yourself only moves where the measurement starts.

open as a page