skip to content

Client Tuning

The client's own settings: the config objects REST Assured exposes, and the switches deciding how it treats HTTPS, key material and proxies. Where a call that works locally fails in CI.

part ofREST Assuredoverview, primer and where to startread it →
on this pageshow

explore

questions

7

In REST Assured, how do you apply a RestAssuredConfig globally, to one specification, and to a single request?

level: juniorimportance: must knowfreq 58%

answer

  1. one object, eighteen smaller ones
  2. three places to hand it over
  3. static field, builder, given()
  4. config() then a chained setter

basics

~20 s

RestAssuredConfig 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 lines
java
import 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

for a junior

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().

for a middle

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.

for a senior

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.

for a principal

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
open as a page

In REST Assured, how do RestAssuredConfig.config() and RestAssured.config() differ when you add a setting?

level: middleimportance: must knowfreq 46%

basics

~20 s

RestAssuredConfig.config() is a factory returning a brand-new, all-default config; RestAssured.config() returns whatever is currently assigned to the static field. Building from the factory silently discards earlier settings, because each setter copies the other seventeen objects forward unchanged.

open as a page

In REST Assured, how do you send a request through a proxy that requires a username and password?

level: middleimportance: should knowfreq 44%

basics

~20 s

REST Assured's short proxy overloads take no credentials. Build a ProxySpecification instead, chaining host, withPort, withScheme and finally withAuth, and hand it to given().proxy(...). Order matters: withScheme rebuilds the specification and silently drops any username and password already set.

open as a page

In REST Assured, what does given().relaxedHTTPSValidation() actually switch off?

level: middleimportance: should knowfreq 52%

basics

~20 s

It replaces REST Assured's SSL socket factory with one built from a trust-all X509TrustManager and Apache HttpClient's allow-all hostname verifier, so both certificate-chain validation and hostname checking stop. The SSLContext protocol defaults to SSL. Nothing else on the request changes.

open as a page

In REST Assured, how can RequestSpecBuilder.setConfig(...) wipe a setting you made in RestAssured.config?

level: seniorimportance: should knowfreq 34%

basics

~20 s

When a specification is merged into a request, REST Assured chooses between the two configs one config object at a time, using each object's isUserConfigured flag. The winner replaces the whole object, so untouched fields inside it revert to defaults.

open as a page

Your REST Assured suite pins a CA with RestAssured.trustStore(...) but accepts a certificate issued for another host. Why?

level: seniorimportance: should knowfreq 34%

basics

~20 s

The path-and-password trustStore and keyStore shortcuts finish by applying allowAllHostnames() for backward compatibility, replacing the strict verifier. Your chain is checked against the pinned authority, but the certificate's subject is never compared with the host you called.

open as a page

In a REST Assured suite, when is relaxedHTTPSValidation() an acceptable choice, and what replaces it?

level: principalimportance: should knowfreq 30%

basics

~20 s

Only where no authority exists to trust: an ephemeral container's self-signed certificate, a local capture proxy, a sandbox you cannot influence. Everywhere else, a trust store with strictHostnames keeps both checks alive and trusts exactly your own issuer.

open as a page