In REST Assured, where do you set a connect or read timeout, given the DSL has no timeout() method?
answer
- not a DSL method at all
- the Apache client owns the clock
- HttpClientConfig is the only seam
- setParam seeds, httpClientFactory replaces
basics
~20 sTimeouts are the Apache HTTP client's, not REST Assured's. Reach them through HttpClientConfig: setParam puts a parameter on the client REST Assured builds, and httpClientFactory replaces that client so you configure it yourself. There is no DSL timeout method.
solid answer
~50 sREST Assured's request DSL has no `timeout(...)`. The time bounds belong to the Apache HttpClient instance underneath, and `io.restassured.config.HttpClientConfig` is the only seam onto it. Two knobs: `httpClientConfig().setParam(name, value)` stores a parameter that REST Assured writes onto the client it has built — the Apache keys `http.connection.timeout` and `http.socket.timeout` are the connect and read bounds — and `httpClientConfig().httpClientFactory(...)` replaces client construction entirely so you configure it in your own factory. Attach the config globally with `RestAssured.config = RestAssured.config().httpClient(...)`, on a shared `RequestSpecBuilder.setConfig(...)`, or per call with `given().config(...)`. Two things this is not: `then().time(matcher)` measures a round trip after it finished and cannot shorten it, and a read timeout bounds one attempt rather than the wait for a tram inspection to reach `SETTLED`. `ConnectionConfig`, despite the promising name, only decides whether idle connections are closed after each response.
code
java · 18 linesimport io.restassured.config.RestAssuredConfig;
import static io.restassured.RestAssured.given;
import static io.restassured.config.HttpClientConfig.httpClientConfig;
import static io.restassured.config.RestAssuredConfig.newConfig;
import static org.hamcrest.Matchers.equalTo;
RestAssuredConfig bounded = newConfig()
.httpClient(httpClientConfig()
.setParam("http.connection.timeout", 2_000)
.setParam("http.socket.timeout", 5_000));
given().config(bounded)
.baseUri("https://fares.tramnet.test")
.pathParam("inspectionId", inspectionId)
.when().get("/inspections/{inspectionId}")
.then().statusCode(200)
.body("status", equalTo("SETTLED"));go deeper
Know that a REST Assured call carries no time limit of its own and that you cannot type a timeout into the chain. Being able to name HttpClientConfig as the place to look is enough at this level.
Explain that REST Assured delegates the wire to an Apache HTTP client, and that HttpClientConfig either seeds that client's parameters or replaces its construction. Say which of the two you would reach for and why.
Show where the config is attached - a shared RequestSpecBuilder, a per-call given().config(...), or the global static - and argue clearly why an elapsed-time assertion is not a time bound.
Decide the suite policy: whether every request carries a bound by default, who owns the numbers, and what a hung call costs a pipeline when nothing below the runner enforces any limit at all.
## Why there is nothing to type in the chain Every part of a REST Assured call is expressed as a method on `RequestSpecification` or on the validatable response, and neither declares a `timeout`. That is not a naming quirk: REST Assured does not open sockets itself. It builds a request, hands it to an Apache HttpClient instance and decorates what comes back. Anything to do with clocks on the wire therefore belongs to that client, and REST Assured's job is only to give you a way to reach it. That way is `io.restassured.config.HttpClientConfig`, one of the eighteen config objects held by `RestAssuredConfig`. The class Javadoc says as much in the first line: it configures the Apache HTTP Client parameters, and it explicitly redirects redirect handling to `RedirectConfig` so the two are not confused. ## The two knobs, and when each one acts | Knob | What it does | When it acts | |---|---|---| | `setParam(name, value)` | stores a key/value pair REST Assured copies onto the built client's parameter object | after the client exists | | `withParams(map)` / `setParams(map)` | replaces the stored pairs wholesale | after the client exists | | `addParams(map)` | merges pairs into the stored set | after the client exists | | `httpClientFactory(factory)` | replaces construction of the client itself | before the client exists | For timeouts against an Apache HttpClient 4.5 client, the parameter names are `http.connection.timeout` (how long to wait for the connection to be established) and `http.socket.timeout` (how long to wait for data once connected). Both are the client library's vocabulary, not REST Assured's — REST Assured passes the map through untouched. The factory route is the escape hatch. The default factory returns a classic `DefaultHttpClient`; yours can return anything, configured however that client's own API expects. The documentation carries one constraint worth remembering: you are expected to supply an `AbstractHttpClient`, because that is the shape whose parameters REST Assured can write into afterwards. ## Where to attach the config There are three attachment points and they differ in blast radius: - `RestAssured.config = RestAssured.config().httpClient(httpClientConfig()...)` sets it for the whole JVM. Simple, and global mutable state — one class changing it changes everyone's requests, which is a hazard once classes run in parallel. - `new RequestSpecBuilder().setConfig(...)` puts it on a specification you attach with `given().spec(fares)`. This is usually the right home for a suite, because the configuration travels with the request. Note that `new RequestSpecBuilder()` snapshots the `RestAssured` statics in its constructor, so a builder created before you assign `RestAssured.config` never sees that assignment. - `given().config(...)` sets it for one call. Explicit and local, at the cost of repeating it. ## Against the tram fare-inspection API Suppose `GET /inspections/{inspectionId}` on the fare service occasionally stops answering rather than answering slowly. Without a bound, the call blocks until the operating system gives up, the test method hangs, and a CI job waits on it. With `setParam("http.socket.timeout", 5000)` the attempt fails in five seconds with a client-level failure, and your suite can decide what that means. What that bound does **not** do is make the inspection settle. Two different clocks are in play, and conflating them is the classic mistake here: 1. The **per-attempt bound** — how long one HTTP call may take before the client abandons it. That is `HttpClientConfig`. 2. The **readiness deadline** — how long you are willing to keep asking before you declare the inspection stuck. REST Assured has no opinion on this at all; it lives in your loop. ## Three things people reach for that are not timeouts - `then().time(lessThan(2000L))` and its `time(matcher, TimeUnit)` overload assert on a round trip that has already completed. REST Assured appends a `TimingFilter` automatically when you have not registered one, so the measurement is always there — but a measurement made after the fact cannot shorten anything. - `ResponseSpecBuilder.expectResponseTime(matcher)` is the same assertion relocated into a response specification. Still after the fact. - `ConnectionConfig` sounds like the right place and is not. It governs whether idle connections are closed after each response (`closeIdleConnectionsAfterEachResponse()` and friends); it holds no timeout values. The practical shape for a suite is therefore: one `RestAssuredConfig` carrying an `HttpClientConfig` with both parameters set, built once, attached through a shared specification, plus a separate deadline in whatever code does the waiting. Two absences, two different fixes.
- Why is then().time(lessThan(2000L)) not a substitute for a read timeout in REST Assured?Because it is a validation, not a limit. REST Assured records the round trip with an automatically appended `TimingFilter` and compares the recorded value once the response has arrived. A call that hangs for ten minutes still hangs for ten minutes and is then reported. A read timeout in `HttpClientConfig` is what actually cuts the attempt short.
- Where would you attach a bounded RestAssuredConfig so every test in a suite inherits it?On a shared `RequestSpecBuilder` via `setConfig(...)`, built once and attached with `given().spec(...)`. Assigning `RestAssured.config` works too but is global mutable state that leaks across parallel classes, and `new RequestSpecBuilder()` snapshots the statics in its constructor, so a builder created before the assignment never sees it.
saying these in an interview costs you the question
- Names a given().timeout(...) or when().timeout(...) method
- Thinks then().time(lessThan(...)) cancels a slow request
- Confuses a per-attempt read timeout with waiting for readiness
- Points at ConnectionConfig, which only closes idle connections
- Sets RestAssured.config inside one test and leaks it across the suite