In REST Assured, what does a queried spec's getDefinedFilters() show and what is missing?
answer
- the word defined is the whole contract
- registration order, not execution order
- SendRequestFilter joins only at dispatch
- unmodifiableList, so add throws
basics
~20 sgetDefinedFilters on REST Assured's QueryableRequestSpecification returns an unmodifiable list of the filters you registered, plus any the specification snapshotted or merged in. The internal filters REST Assured appends at send time, including SendRequestFilter, are not there yet.
solid answer
~50 sThe getter is `getDefinedFilters()` — there is no `getFilters()` on `QueryableRequestSpecification`, and the word *defined* is the contract. It reports, in registration order, filters added with `given().filter(...)` or `RequestSpecBuilder.addFilter(...)`, filters the builder snapshotted from the static `RestAssured.filters()` list at construction, and filters a merged-in specification contributed, since filters accumulate across `spec(...)`. It does **not** report what REST Assured appends at dispatch: `SendRequestFilter` (the one that actually sends), `TimingFilter`, the form-auth and CSRF filters, and validation-failure logging filters. The list comes back through `Collections.unmodifiableList`, so `add` throws `UnsupportedOperationException`; you change the set with `filter(...)`, `noFilters()` or `noFiltersOfType(...)` on the specification. Because REST Assured sorts the chain by each filter's order value just before dispatch, you read back registration order, not execution order — assert membership rather than index. The practical payoff is a fast guard test proving a shared greenhouse specification still carries its audit and cookie filters.
code
java · 15 linesRequestSpecification climateSpec = new RequestSpecBuilder()
.setBaseUri("https://climate.greenhouse.test")
.addFilter(new RequestLoggingFilter())
.addFilter(new CookieFilter())
.build();
List<Filter> defined = SpecificationQuerier.query(climateSpec).getDefinedFilters();
defined.size(); // 2 - registration order
defined.get(0).getClass(); // RequestLoggingFilter
defined.add(new ResponseLoggingFilter()); // UnsupportedOperationException
// change the set through the specification, then read it back
climateSpec.noFiltersOfType(CookieFilter.class);
SpecificationQuerier.query(climateSpec).getDefinedFilters().size(); // 1go deeper
Remember the exact name: getDefinedFilters, on QueryableRequestSpecification. Know it lists the filters registered on the specification and that the returned list cannot be modified.
Explain the three sources that populate it — direct registration, the static snapshot taken in the builder constructor, and filters accumulated through a merge — and name one filter that is added only at dispatch.
Use it as a guard: a fast test asserting that a shared specification carries exactly the filters the suite depends on, catching drops, duplicates and late static registrations before an integration run does.
Decide where cross-cutting request behaviour lives at all — static filters, a shared specification, or explicit per-call registration — and what the suite asserts about that choice so it stays true as the suite grows.
## Get the name right first The method is `getDefinedFilters()`. There is no `getFilters()` on `io.restassured.specification.QueryableRequestSpecification`, and guessing that shorter name is the usual reason a first attempt at introspecting filters will not compile. The word *defined* is not decoration — it is the whole contract. The list holds the filters that were **defined on the specification**, which is a strictly smaller set than the filters that will run when the request goes out. ## What is in the list A queried greenhouse climate specification reports, in registration order: - Filters added directly, with `given().filter(...)`, `given().filters(...)` or `RequestSpecBuilder.addFilter(...)` / `addFilters(...)`. - Filters that `new RequestSpecBuilder()` snapshotted from the static `RestAssured.filters()` list in its constructor. A builder constructed *before* a static filter was registered will not have it — the snapshot happens once, at construction. - Filters contributed by a merged-in specification. Filters accumulate across `spec(...)` rather than being replaced, so `given().filter(a).spec(specWithB)` reports both. Every entry is a real `io.restassured.filter.Filter` instance, so you can assert on its class, or on its state if you wrote it yourself. ## What is not in the list REST Assured assembles the actual filter chain when the request is dispatched, not when the specification is built. Everything below is appended at that point and is therefore invisible to a querier used beforehand: | Filter | When it is added | |---|---| | `SendRequestFilter` | appended last on every request — it is the filter that actually sends | | `TimingFilter` | appended unless you registered one yourself | | `FormAuthFilter` | inserted first when the authentication scheme is form auth | | `CsrfFilter` | appended when CSRF handling is switched on for the request | | `RequestLoggingFilter` / `ResponseLoggingFilter` | added when validation-failure logging is enabled and no equivalent filter is present | This is the mechanical reason a filter chain cannot be fully audited from a specification. What you *can* audit is the half you control, which is the half that goes wrong. ## The list is unmodifiable `getDefinedFilters()` returns `Collections.unmodifiableList(...)` over the specification's own filter list. Two consequences: - `add(...)` or `remove(...)` on the returned list throws `UnsupportedOperationException`. It is a read surface, not a back door. - To change the set you go through the specification: `filter(...)` to add, `noFilters()` to clear everything, and `noFiltersOfType(CookieFilter.class)` to drop one kind. Query again afterwards and the list reflects the change, because the view is live rather than a snapshot. Inside a filter you have a `FilterableRequestSpecification`, which extends the queryable interface and adds mutators for headers, cookies and parameters — but the filter list itself is still reached through the same `noFilters` / `noFiltersOfType` calls on the specification. ## Registration order is not execution order The order you read back is the order things were registered. Just before dispatch, REST Assured sorts the chain by each filter's order value, so a filter implementing `OrderedFilter` can move. Two rules of thumb follow: - Assert on **membership** — that the greenhouse suite's audit filter and cookie filter are both present — rather than on their positions in the returned list. - If ordering is what you are worried about, assert the order values of the filters you registered, not their index in `getDefinedFilters()`. ## What this is good for The realistic use is a guard test on a shared specification. A greenhouse climate suite that expects every call to carry its audit filter and its cookie filter can assert exactly that in a few milliseconds, with no server: - It catches a filter dropped during a refactor of the specification factory. - It catches a static filter registered too late to be snapshotted by an already-constructed builder. - It catches a duplicate registration — the same logging filter added both statically and per-suite shows up twice in the list. Each of those would otherwise surface as a strange behavioural difference in a long integration run, which is a far more expensive place to find it. ## The shape of the check Keep the assertion coarse and it stays useful for years: ```java List<Filter> defined = SpecificationQuerier.query(climateSpec).getDefinedFilters(); assertThat(defined).hasAtLeastOneElementOfType(CookieFilter.class); ``` Asserting a class is present survives refactoring; asserting `defined.get(1)` does not. If you care that a specific instance was registered — a filter carrying the greenhouse site id, say — cast the element and assert its state, since the list holds the real objects rather than descriptions of them. And if the question you are really asking is *what does this suite attach to every request*, query `getDefinedFilters()` and `getConfig()` together: between them they describe the whole cross-cutting layer a specification imposes, with no request sent and nothing to interpret.
- How would you check that a filter registered on RestAssured.filters() reached a shared specification?Query the built specification and look for its class in `getDefinedFilters()`. `new RequestSpecBuilder()` snapshots the static filter list once, in its constructor, so a builder created before the static registration will not carry it — and the read-back is what makes that ordering bug visible instead of mysterious.
- Why can you not audit the whole filter chain from a specification?Because REST Assured assembles the executed chain at dispatch. `SendRequestFilter`, `TimingFilter`, the form-auth and CSRF filters and the validation-failure logging filters are appended then, and the chain is sorted by order at the same moment. A specification only knows the filters that were defined on it.
saying these in an interview costs you the question
- Calls the method getFilters, which does not exist on the interface
- Expects SendRequestFilter to appear on an unsent specification
- Removes a filter by calling remove on the returned list
- Reads the list index as the execution order of the chain
- Assumes a builder always sees statics registered after it was constructed