skip to content

Harness Placement

Everything around a single call: how the REST Assured client itself is configured, and how the library sits inside a build and a suite. It separates DSL users from harness owners.

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

explore

questions

16

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 you wait for a tram fare-inspection to become SETTLED before asserting?

level: middleimportance: must knowfreq 62%

basics

~20 s

REST Assured has no retry, no polling and no timeout method on its request DSL. You write the waiting yourself, in a bounded loop or a library such as Awaitility, and REST Assured supplies each call and the final assertion.

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

When a REST Assured expectation fails, what is thrown and how does JUnit 5 or TestNG see it?

level: middleimportance: must knowfreq 66%

basics

~20 s

REST Assured throws a plain java.lang.AssertionError whose message opens with a count of failed expectations and lists each mismatch. Nothing catches it, so it unwinds out of the test method and the runner that called that method records a failure.

open as a page

Why should a REST Assured polling loop not use then().statusCode(200) as its loop condition?

level: seniorimportance: must knowfreq 47%

basics

~20 s

Because REST Assured validation is not a boolean: a failed expectation throws AssertionError. Using it as a loop condition means catching AssertionError every iteration, which silently swallows real failures as not-ready-yet and ends with a timeout message naming nothing.

open as a page

In REST Assured, where do you set a connect or read timeout, given the DSL has no timeout() method?

level: seniorimportance: must knowfreq 54%

basics

~20 s

Timeouts 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.

open as a page

Which io.rest-assured coordinate does a REST Assured test project depend on, and what comes with it?

level: juniorimportance: should knowfreq 62%

basics

~20 s

The one coordinate io.rest-assured:rest-assured at test scope covers API testing; it brings json-path, xml-path, Groovy, Apache HttpClient and Hamcrest with it. Object mapping, JSON schema validation, Kotlin blocks and Spring support are separate artifacts, and no test runner is included.

open as a page

In REST Assured, why does a Java then() chain report one failed expectation but the Kotlin Then block all of them?

level: middleimportance: should knowfreq 38%

basics

~20 s

The Java chain validates eagerly: each expectation is checked as it is added, so the first mismatch throws and the rest never run. The kotlin-extensions Then block disables that, collects everything, then validates once, so one AssertionError lists every failure.

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 do httpClientConfig().setParam(...) and httpClientFactory(...) differ for timeouts?

level: seniorimportance: should knowfreq 39%

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.

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

A REST Assured suite dies with NoSuchMethodError on an org.hamcrest class — how do you fix it?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Two Hamcrest jars are on the test classpath and the older one is winning. REST Assured needs the modern org.hamcrest:hamcrest artifact; a legacy hamcrest-core or hamcrest-all 1.x jar supplies the same classes. Exclude or pin one Hamcrest and it goes.

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

REST Assured ships no retry or timeout DSL - how would you wire waiting across a large suite?

level: principalimportance: should knowfreq 35%

basics

~20 s

REST Assured leaves two gaps and a suite should fill them separately: a per-attempt time bound carried by one shared RestAssuredConfig, and a readiness wait in one helper that extracts values while the real expectations stay outside it.

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