skip to content

In REST Assured, how do httpClientConfig().setParam(...) and httpClientFactory(...) differ for timeouts?

level: seniorimportance: should knowfreq 39%

answer

  1. one seeds, the other replaces
  2. the factory runs before the parameters land
  3. parameters need a parameter-aware client
  4. a new client per given by default

basics

~20 s

REST Assured's setParam stores an entry it writes onto the parameters of the client it already built, so the client must accept them. httpClientFactory replaces construction, letting you configure timeouts inside your own factory before REST Assured sees it.

solid answer

~50 s

They act at different moments. `httpClientConfig().setParam(name, value)` stores a key/value pair; when REST Assured builds a request it asks the configured factory for a client and then writes those pairs onto that instance's parameter object. `httpClientConfig().httpClientFactory(...)` replaces the construction step itself — the default factory returns a classic `DefaultHttpClient`, and yours may return anything, configured however that client's own API wants. For timeouts the consequence is concrete: `setParam` only lands if the client honours a mutable parameter object, which is why the documentation still says you must supply an `AbstractHttpClient`. There is a cost dimension too — REST Assured creates a new client for each `given()` unless the config says `reuseHttpClientInstance()`, so a long poll against a tram fare-inspection builds one client per attempt. Neither knob makes the library wait, though: both of them bound a single attempt, and the repetition is still yours.

code

java · 21 lines
java
import io.restassured.RestAssured;
import io.restassured.config.HttpClientConfig;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.SystemDefaultHttpClient;

import static io.restassured.config.HttpClientConfig.httpClientConfig;

// (a) seed the client REST Assured builds for you
RestAssured.config = RestAssured.config().httpClient(
        httpClientConfig().setParam("http.socket.timeout", 5_000));

// (b) or build and configure the client yourself
RestAssured.config = RestAssured.config().httpClient(
        httpClientConfig().httpClientFactory(new HttpClientConfig.HttpClientFactory() {
            @Override
            public HttpClient createHttpClient() {
                SystemDefaultHttpClient client = new SystemDefaultHttpClient();
                client.getParams().setParameter("http.socket.timeout", 5_000);
                return client;
            }
        }).reuseHttpClientInstance());

go deeper

for a junior

Know that both live on HttpClientConfig and that REST Assured itself does not implement timeouts. Being able to say the library delegates to an Apache HTTP client is the level-appropriate answer here.

for a middle

Explain the ordering: the factory produces the client, then REST Assured writes the stored parameters onto it. That ordering is what decides whether setParam has anything to act on.

for a senior

Diagnose the silent case - a parameter that appears set and does nothing - and know that a poll builds one client per given() unless a statically-defined config asks for reuse.

for a principal

Decide what the harness owns: a single client factory the whole suite shares, or per-test configuration. Weigh the reuse and isolation tradeoff, especially once test classes run in parallel.

## Two seams onto the same object `io.restassured.config.HttpClientConfig` is REST Assured's only door onto the Apache HttpClient instance that actually moves bytes. It offers that door twice, at two different moments in the request's life, and the difference is the whole answer. - `httpClientFactory(HttpClientFactory)` replaces **how the client is created**. The interface has a single method, `HttpClient createHttpClient()`. REST Assured's own default implementation returns `new DefaultHttpClient()`. - `setParam(name, value)` — with `addParams(map)`, `withParams(map)` and `setParams(map)` alongside it — stores entries in a map that REST Assured writes onto the client **after** it has been created. Read in order, a request does this: it asks the configured factory for a client, then copies each stored parameter onto that client's parameter object, then sends. The factory runs first; the parameters are applied second. ## Why the order matters for timeouts The connect and read bounds for an Apache HttpClient 4.5 client are the parameters `http.connection.timeout` and `http.socket.timeout`. Setting them through `setParam` works precisely because the classic client hierarchy exposes a mutable parameter object that REST Assured can write into after construction. The moment your factory returns something else, that assumption can quietly stop holding, and the documentation says so directly: it notes that you are expected to supply an `AbstractHttpClient`. So: | You want to… | Use | Why | |---|---|---| | set a couple of standard parameters | `setParam(...)` | REST Assured writes them onto the client it built for you | | use a client configured a different way | `httpClientFactory(...)` | you construct and configure it yourself, before REST Assured sees it | | do both | factory plus `setParam` | but only if the factory's client accepts written parameters | The failure mode is not an exception you can grep for; it is a setting that appears to be configured and has no effect. If a bound you set through `setParam` does not seem to apply, the first thing to check is what your factory returns. ## The polling-specific consequence There is a second fact in this config object that matters more here than almost anywhere else in the library: by default **REST Assured creates a new HTTP client instance for every `given()` statement**. That is fine for a suite of ordinary one-shot calls. It is conspicuous in a wait loop. Suppose you poll `GET /inspections/{inspectionId}` on the tram fare service every 500 ms for twenty seconds: 1. Forty iterations means forty client instances, each built by your factory. 2. Each one brings its own connection management, and nothing is pooled between attempts. 3. If your factory does expensive work — reading a trust store, building an SSL context — you pay for it forty times. `httpClientConfig().reuseHttpClientInstance()` is the setting that changes this, and the documentation adds one condition: the configuration must be defined statically for the reuse to take effect, because the instance is held on the config object itself. `dontReuseHttpClientInstance()` restores the default. ## When a bound looks configured and is not This is the diagnosis worth rehearsing, because nothing throws. A parameter that never reached the client produces exactly the same behaviour as no parameter at all: the call hangs, and the config object cheerfully reports the value you set. Work through it in order: 1. Confirm which factory is in play. If you never called `httpClientFactory(...)`, it is the default one and the classic client will accept the parameters. 2. If you did, check what your factory returns and whether that client honours a written parameter object at all — the documentation asks for an `AbstractHttpClient` for exactly this reason. 3. Confirm the config actually reached the request. A `RestAssuredConfig` set on a builder constructed earlier, or attached to a specification the call never used, is a common and silent miss. 4. If the client is one you build, move the bound inside the factory and stop relying on `setParam` for it. ## Where each one belongs in a suite - Standard timeout parameters that every request should carry: `setParam` on one shared config, attached through a `RequestSpecBuilder`. - Anything the client's own API expresses better than a parameter map — a custom SSL context, a connection manager, an interceptor: the factory. - Reuse across a long poll: `reuseHttpClientInstance()` on a statically-defined config, once, not per test. ## The boundary worth stating out loud None of this makes REST Assured wait. A bound configured either way limits **one attempt**. If `GET /inspections/{inspectionId}` answers `200` with `"status": "PENDING"` inside 40 ms, every timeout in the world is irrelevant — the call succeeded, it just did not say what you wanted. The repetition still comes from a loop you wrote. Timeouts and waiting are two different absences in this library, and reaching for the config object to solve the second one is the mistake this question exists to catch.

  • How many HTTP client instances does a forty-attempt REST Assured poll create by default?
    Forty. REST Assured builds a new client for each `given()` statement unless the configuration says `reuseHttpClientInstance()`, and the documentation adds that the config must be defined statically for the reuse to take effect. In a wait loop that is the difference between one client and one per attempt, including any expensive setup your factory does.
  • You set http.socket.timeout with setParam and nothing changed. What do you check first?
    What your `httpClientFactory` returns. The parameters are written onto the client after it is constructed, so they only take effect on a client that exposes a mutable parameter object — the documentation says to supply an `AbstractHttpClient`. If the factory returns something else, configure the bound inside the factory instead.

saying these in an interview costs you the question

  • Thinks setParam configures REST Assured rather than the HTTP client
  • Expects setParam to apply to any client the factory returns
  • Assumes one HTTP client is shared across every request by default
  • Sets the factory on a per-request config and still expects instance reuse
  • Treats a client timeout as the readiness wait for an async resource