In REST Assured, how do you apply a RestAssuredConfig globally, to one specification, and to a single request?
answer
- one object, eighteen smaller ones
- three places to hand it over
- static field, builder, given()
- config() then a chained setter
basics
~20 sRestAssuredConfig applies at three scopes: assign it to the static RestAssured.config field for every request, pass it to RequestSpecBuilder.setConfig for one reusable specification, or hand it to given().config for a single call. A narrower scope overrides a wider one.
solid answer
~50 s`RestAssuredConfig` is one immutable object holding **eighteen** smaller config objects — `RedirectConfig`, `HttpClientConfig`, `DecoderConfig`, `ConnectionConfig`, `ObjectMapperConfig` and the rest. You build one from the static factory `RestAssuredConfig.config()` (`newConfig()` is its twin) and chain a setter such as `redirect(...)` or `httpClient(...)`; each setter returns a new instance carrying the other seventeen forward, so nothing is ever mutated. Applying it has three scopes. Globally, assign the field: `RestAssured.config = config().redirect(redirectConfig().maxRedirects(3))`, and every later `given()` is seeded from it. Per specification, `new RequestSpecBuilder().setConfig(...)` bakes it into a reusable `RequestSpecification` that merges into a call at `given().spec(...)`, one config object at a time. Per request, `given().config(...)` swaps the whole config for that one call, with no merging at all. On a marina berth-booking suite I keep decoding and HTTP-client tuning global and reserve `given().config(...)` for the one endpoint that genuinely differs.
code
java · 23 linesimport static io.restassured.RestAssured.given;
import static io.restassured.config.RedirectConfig.redirectConfig;
import static io.restassured.config.HttpClientConfig.httpClientConfig;
// 1) global - seeds every given() built after this line
RestAssured.config = RestAssured.config()
.redirect(redirectConfig().maxRedirects(3));
// 2) per specification - merged in, object by object, at given().spec(...)
RequestSpecification berthSpec = new RequestSpecBuilder()
.setBaseUri("https://api.harbourside-marina.test")
.setConfig(RestAssured.config()
.httpClient(httpClientConfig().reuseHttpClientInstance()))
.build();
// 3) per request - replaces the whole config for this one call
given().spec(berthSpec)
.config(RestAssured.config()
.redirect(redirectConfig().followRedirects(false)))
.when()
.get("/berths/{berthId}", "D-14")
.then()
.statusCode(200);go deeper
Be ready to write the three lines from memory: assigning RestAssured.config, calling setConfig on a RequestSpecBuilder, and passing given().config on one call. Know that a config is built from RestAssuredConfig.config().
Explain that each setter returns a new RestAssuredConfig rather than mutating one, and that given().config replaces the whole config while a specification is merged object by object.
Show where you would place each setting in a real suite, and how you keep a per-request override from quietly discarding the suite-wide configuration around it.
Own the convention: one place per scope, written down, so nobody adds a fourth. Argue why configuration scattered across setup methods costs more than the duplication it removes.
## What `RestAssuredConfig` actually is `io.restassured.config.RestAssuredConfig` is one immutable container holding **exactly eighteen** smaller configuration objects, each responsible for one slice of the library's behaviour: - `ConnectionConfig`, `CsrfConfig`, `DecoderConfig`, `EncoderConfig`, `FailureConfig`, `HeaderConfig` - `HttpClientConfig`, `JsonConfig`, `LogConfig`, `MatcherConfig`, `MultiPartConfig`, `OAuthConfig` - `ObjectMapperConfig`, `ParamConfig`, `RedirectConfig`, `SSLConfig`, `SessionConfig`, `XmlConfig` Internally the container is a map keyed by config type, and every value in it is itself immutable, so the whole tree of settings can be shared between requests without anyone copying it defensively. The package directory holds twenty `.java` files, which is where the common wrong answer of "twenty" comes from: the two extras are `RestAssuredConfig` itself and the one-method `Config` interface that all eighteen implement. Note what is **not** on the list — there is no `authConfig(...)`. Credentials are not a config object in REST Assured; they live on `RestAssured.authentication` and `given().auth()`. ## Building one `RestAssuredConfig` exposes two static factories that do exactly the same thing: `config()` and `newConfig()` both return a brand-new instance with all eighteen objects at their defaults. Each of the eighteen classes carries a matching static factory of its own — `redirectConfig()`, `httpClientConfig()`, `decoderConfig()`, `connectionConfig()` and so on — so a configured instance reads as one chained sentence once both levels are statically imported. Three naming details trip people up: - Sixteen of the setters are the class name in lower camel case (`logConfig(...)`, `paramConfig(...)`, `csrfConfig(...)`), but `redirect(RedirectConfig)` and `httpClient(HttpClientConfig)` **drop the `Config` suffix**. - Every getter keeps it, and keeps the class's own capitalisation: `getRedirectConfig()`, `getHttpClientConfig()`, `getSSLConfig()`, `getOAuthConfig()`. - `and()`, `with()` and `set()` on `RestAssuredConfig` are pure readability sugar — all three `return this`. Every setter returns a **new** `RestAssuredConfig` carrying the other seventeen objects forward. Nothing is mutated, so a chain never loses what an earlier link set, and a chain whose result you never assign changes nothing at all. ## The three scopes | Scope | How you apply it | What it reaches | |---|---|---| | Global | `RestAssured.config = ...` | every `given()` built after that line | | Per specification | `new RequestSpecBuilder().setConfig(...)` | every call that uses `given().spec(spec)` | | Per request | `given().config(...)` | that single call only | **Global** is a plain public static field. Assign it once in a suite-wide setup hook and every request built afterwards starts from it, because `RestAssured.given()` seeds the new request specification with whatever `RestAssured.config()` returns at that moment. **Per specification** goes through `RequestSpecBuilder.setConfig(...)`, which stores the config on the specification being built. Two things are worth knowing here. First, `new RequestSpecBuilder()` snapshots the current global config in its constructor, so a builder constructed before you assign `RestAssured.config` never sees the assignment. Second, when the finished specification meets a call at `given().spec(spec)`, configuration is merged **one config object at a time** — only the objects the specification actually touched replace the request's. **Per request** is `given().config(...)` on the `RequestSpecification`. This one does not merge at all: it assigns the whole `RestAssuredConfig` onto that request, replacing all eighteen objects in one go. That is why the idiomatic form is `given().config(RestAssured.config().redirect(...))` — starting from the currently assigned global config rather than from a fresh `RestAssuredConfig.config()` keeps everything else the suite had already set. Written the other way, one per-request override quietly reverts the other seventeen objects to their defaults for that call, and the only symptom is a test that behaves unlike its neighbours. ## The knobs this surface owns outright Most of the eighteen are the front door of some other subject — mapping, logging, matchers, sessions. Four are configuration in the plain sense: - `RedirectConfig` — `followRedirects(boolean)`, `maxRedirects(int)` (default 100), `allowCircularRedirects(boolean)`, `rejectRelativeRedirect(boolean)`. - `HttpClientConfig` — `reuseHttpClientInstance()` and `dontReuseHttpClientInstance()`, `httpClientFactory(...)`, `setParam(name, value)`, `httpMultipartMode(...)`. REST Assured builds a new Apache HTTP client for each `given()` unless you opt into reuse. - `DecoderConfig` — `contentDecoders(...)` and `noContentDecoders()`. The `ContentDecoder` enum has two values, `GZIP` and `DEFLATE`, and both are enabled unless you replace the list. - `ConnectionConfig` — `closeIdleConnectionsAfterEachResponse()` and its timed overload. ## Placing it in a real suite For a marina berth-booking suite, the split that survives contact with reality is: 1. Anything true of the whole service goes in the global config — decoders, HTTP-client reuse, redirect policy. 2. Anything true of one API area goes on that area's `RequestSpecification`, next to its base URI and its headers. 3. `given().config(...)` is reserved for the one call that genuinely differs — the `POST /bookings` that must not follow the redirect to `/bookings/{bookingId}`, say. Keeping the layers in that order means a reader of one failing test can answer "where did this setting come from?" by looking in exactly three places, in a fixed order, instead of grepping the suite. The order is also the order of blast radius, which makes review easy: a change to the global config deserves scrutiny from everyone, a change to one specification from the people who own that endpoint, and a per-request override from nobody but the test's author.
- Which of the eighteen config objects holds the credentials a request sends?None of them. `RestAssuredConfig` declares no `authConfig(...)` setter and the config package has no authentication config class. Credentials are set through `given().auth()` or the static `RestAssured.authentication` field, which is a separate part of the request specification entirely. `OAuthConfig` is the nearest thing on the roster, and it holds OAuth signing settings rather than the credential itself.
- How would you tell whether any of the eighteen config objects has actually been changed?Every config class implements `Config`, whose only method is `isUserConfigured()`. It returns `false` for an object built by its no-arg constructor and `true` once any of its chained setters has been called. `RestAssuredConfig.isUserConfigured()` aggregates: it returns `true` if any one of the eighteen reports `true`. REST Assured uses that same flag when merging a specification into a request.
saying these in an interview costs you the question
- Thinks RestAssuredConfig has a setter for every option, including authentication
- Believes the chained setters mutate the config object in place
- Says given().config(...) merges with whatever the request already had
- Counts twenty config objects from the package's file listing
- Assumes a RequestSpecBuilder picks up a global config assigned after it was built