In REST Assured, what does TimingFilter record, and what changes when you register it yourself?
answer
- measures around its own ctx.next(...)
- writes into the filter context, prints nothing
- one is appended automatically, last
- registering it relocates the window
basics
~20 sREST 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.
solid answer
~40 s`TimingFilter` prints nothing. It takes `System.currentTimeMillis()` before `ctx.next(...)` and after, and puts the difference into the filter context under the key `RA_RESPONSE_TIME_MILLIS`, which is what `Response.time()` reads back. The part people miss is that REST Assured **appends one for you** if the filter list does not already contain one, and it appends it last, immediately before the internal filter that actually sends. So the automatic instance measures the send and nothing else. Registering `TimingFilter.measureTime()` yourself moves the measurement to wherever you put it in the chain, so it also covers every filter downstream of that point. The other constructor, `new TimingFilter(true)`, consumes a streamed response body before stopping the clock, so download time is included. None of this switches timing on or off; it only decides which work falls inside the measured window.
code
java · 29 linesimport io.restassured.filter.log.ResponseLoggingFilter;
import io.restassured.filter.time.TimingFilter;
import io.restassured.response.Response;
import static io.restassured.RestAssured.given;
public class SlotInventoryTiming {
// registered FIRST, so the window also covers the pretty-printing below it
public long timeIncludingLogging() {
Response response = given()
.baseUri("https://api.museum.example")
.filter(TimingFilter.measureTime())
.filter(new ResponseLoggingFilter())
.get("/v1/exhibitions/{exhibitionId}/slots", "pompeii");
return response.time();
}
// no TimingFilter registered: REST Assured appends one last, after the logger
public long timeExcludingLogging() {
Response response = given()
.baseUri("https://api.museum.example")
.filter(new ResponseLoggingFilter())
.get("/v1/exhibitions/{exhibitionId}/slots", "pompeii");
return response.time();
}
}go deeper
Know that TimingFilter measures how long a call took and stores the number rather than printing it, and that REST Assured already adds one for you so response times work out of the box.
Explain the mechanics: it brackets its own ctx.next(...) call, writes the milliseconds into the filter context under RA_RESPONSE_TIME_MILLIS, and is appended automatically only when no TimingFilter is already registered.
Show that you know placement decides the window. Be ready to say what a reported number includes, why two runs with different filter chains are not comparable, and when new TimingFilter(true) is the right constructor.
Decide whether a functional API suite should report latency at all. If the number gets watched, define which quantity it is and fix the chain that produces it, or move performance measurement somewhere built for it.
`TimingFilter` is the odd one out among REST Assured's seven shipped filters: it is the only one that neither prints nor carries state forward. It measures, writes one number into a per-call scratchpad, and gets out of the way. The senior version of this question is not *what does it measure* but *what is inside the window it measures*, and that is a placement question. ## The mechanism, exactly Its `filter(...)` method is five statements: 1. `long start = System.currentTimeMillis()`. 2. `Response response = ctx.next(requestSpec, responseSpec)`. 3. Optionally, if the filter was built with `new TimingFilter(true)` and the response body is still an input stream, call `response.asByteArray()` to drain it. 4. `long end = System.currentTimeMillis()`, and the difference is the response time. 5. `ctx.setValue(TimingFilter.RESPONSE_TIME_MILLISECONDS, responseTime)`, where that constant is the string `"RA_RESPONSE_TIME_MILLIS"`. The value goes into the filter context for that one call. `Response.time()` looks the key up and returns `-1` when it is absent. The static factory `TimingFilter.measureTime()` is just `new TimingFilter()`. ## The part that surprises people: it is already there You do not have to register `TimingFilter` for response times to work. When REST Assured assembles the filter chain, after sorting by precedence it checks the list and appends its own `TimingFilter` if none is present, then appends the internal filter that performs the send. Two consequences follow: - **The automatic instance is last.** Its window contains the send and the response read, and nothing else in your chain. - **Registering one yourself suppresses the automatic append**, because the check is for any filter assignable to `TimingFilter`, not for a specific object. So `given().filter(TimingFilter.measureTime())` does not *enable* timing. It **relocates** it. ## What placement changes | Where the TimingFilter sits | What the measured window contains | | --- | --- | | Appended automatically (last) | The send and the response read only | | Registered first, before other filters | Every downstream filter plus the send | | Registered after a logging filter | The send, and the response printing that happens after | | Built as `new TimingFilter(true)` | Also the time to drain a streamed response body | On a museum ticketing suite this is a real decision. If `GET /v1/exhibitions/{exhibitionId}/slots` returns a large slot inventory and a `ResponseLoggingFilter` pretty-prints it, that printing happens on the way back out through the chain. A `TimingFilter` registered before the logging filter includes the pretty-printing cost in the number; the automatic one, sitting after it, does not. Neither is wrong -- but reporting the first as *"the API's response time"* is. ## Why this matters in production judgment The reason this reaches senior level is that timing numbers get acted on. A few habits keep them honest: - **Decide what the number means before you measure.** Server latency, client-observed latency and end-to-end harness cost are three different quantities, and filter placement picks which one you get. - **Do not compare numbers taken with different chains.** A suite that adds a logging filter in CI but not locally is comparing two different windows. - **Remember the resolution.** `System.currentTimeMillis()` is millisecond-granular wall clock, which is fine for a several-hundred-millisecond HTTP call and useless for micro-benchmarking. - **Remember what is outside every window.** Connection setup pooled by the HTTP client, DNS, and TLS handshakes may or may not fall inside a given call, so early requests in a run read high. - **Do not use it as a performance test.** A functional suite measuring latency in passing is a smoke signal, not a load test. ## Constructors and factory, in full The class's public surface is small, which makes it easy to state precisely in an interview: 1. `new TimingFilter()` -- do not drain a streamed response before stopping the clock. 2. `new TimingFilter(true)` -- drain an input-stream response first, so its download time is inside the window. 3. `TimingFilter.measureTime()` -- the static factory, equivalent to the no-argument constructor. 4. `TimingFilter.RESPONSE_TIME_MILLISECONDS` -- the public constant naming the filter-context key. The compact answer: it times its own `ctx.next(...)` and writes the result into the filter context; REST Assured already appends one at the end of the chain for you; registering it yourself is about moving the start of the window, not about switching timing on.
- If TimingFilter is appended automatically, when would you ever register it explicitly?When you want a different window or different behaviour. Registering it first makes the measurement cover every downstream filter as well as the send, which is what you want if a filter of yours does expensive work. And `new TimingFilter(true)` drains a streamed response body before stopping the clock, so a large download is inside the number rather than outside it.
- What does TimingFilter print, and where does the number end up?It prints nothing at all -- it is the only shipped filter that produces no output and stores no cross-request state. The elapsed milliseconds go into that call's filter context under the key `RA_RESPONSE_TIME_MILLIS`, and `Response.time()` reads the key back, returning -1 if nothing recorded a value.
saying these in an interview costs you the question
- Thinking TimingFilter prints the elapsed time to the console
- Believing response times are unavailable unless you register it
- Assuming the measured window is server processing time
- Missing that registering it suppresses the automatic instance
- Treating millisecond wall-clock numbers as benchmark quality