skip to content

In REST Assured's RequestSpecBuilder, what is the difference between its addX and setX methods?

level: juniorimportance: should knowfreq 45%

answer

  1. prefix tells you what a repeat call does
  2. set fills a slot, add appends
  3. no setHeader, no removeHeader
  4. remove exists only for parameters

basics

~20 s

RequestSpecBuilder's setX methods fill a single slot, so a second call replaces the first: setBaseUri, setBasePath, setPort, setContentType, setAuth, setBody, setConfig. Its addX methods append to a collection, so repeated calls accumulate: addHeader, addCookie, addQueryParam, addFilter, addMultiPart.

solid answer

~50 s

The prefixes are a contract, not a house style. A `setX` method fills one slot and a second call overwrites the first — `setBaseUri`, `setBasePath`, `setPort`, `setContentType`, `setAccept`, `setAuth`, `setBody`, `setConfig`, `setSessionId`, `setProxy`. An `addX` method appends to a collection, so two calls leave two entries — `addHeader`, `addCookie`, `addParam`, `addQueryParam`, `addFormParam`, `addPathParam`, `addMultiPart`, `addFilter`, `addRequestSpecification`. The split mirrors the specification underneath: a base URI is one value, headers and filters are lists. The surface is deliberately incomplete in one direction — there is no `setHeader`, `setCookie` or `setFilter`, and removal exists only for parameters (`removeParam`, `removeQueryParam`, `removeFormParam`, `removePathParam`). So a template that must not carry a header has to be built without it; you cannot subtract one afterwards. In review the prefix is the fastest tell: a repeated `setX` is dead code, a repeated `addX` is usually a duplicate on the wire, and both look identical at a glance.

go deeper

for a junior

Know that setX overwrites and addX accumulates, and be able to sort the common builder methods into the two groups on sight. That alone prevents duplicate headers and silently lost base paths.

for a middle

Explain why the split exists — single-valued fields versus collections on the underlying specification — and name the gap: no setHeader, no removeHeader, removal only for parameters.

for a senior

Use the asymmetry when you design templates. Be ready to argue why a maximal shared specification fails in practice, since cases cannot strip headers or filters off it, and what composition you use instead.

for a principal

Own the convention across a suite: which values are allowed in a shared template at all, and how teams add setup without reaching every test. The unstrippable half of the builder is what makes that a policy question rather than a style one.

## Two prefixes, two behaviours `io.restassured.builder.RequestSpecBuilder` names its methods to a rule rather than a house style, and the rule tells you what a second call does. A `setX` method fills one slot on the specification being assembled, so calling it again overwrites what was there. An `addX` method appends to a collection, so calling it again leaves both entries in place. Once you read the prefix that way, most of the builder's surface stops needing to be memorised. ## The set family: one slot each These carry a single value, and the last call wins: - `setBaseUri(String)` / `setBaseUri(URI)`, `setBasePath(String)`, `setPort(int)` — where the call lands. - `setContentType(ContentType|String)`, `setAccept(ContentType|String)`, `setBody(...)` — how the payload is described. - `setAuth(AuthenticationScheme)`, `setSessionId(...)` — who the caller is. - `setConfig(RestAssuredConfig)`, `setProxy(...)`, `setUrlEncodingEnabled(boolean)`, `setKeyStore(...)`, `setTrustStore(...)` — transport-level switches. So a template that calls `setBasePath("/v2")` and later `setBasePath("/v2/depot")` carries only `/v2/depot`. That is usually what you want; it is also why a stray second call is silent rather than loud. ## The add family: append and keep These back onto lists or maps on the specification: - `addHeader(name, value)` and `addHeaders(Map)` - `addCookie(...)` (four overloads) and `addCookies(...)` - `addParam`, `addQueryParam`, `addFormParam`, `addPathParam` and their plural and `Map` forms - `addMultiPart(...)` in its several overloads - `addFilter(Filter)` and `addFilters(List<Filter>)` - `addRequestSpecification(RequestSpecification)` Calling `addHeader("X-Depot", "kirkstall")` and then `addHeader("X-Depot", "headingley")` on a milk-round template leaves **two** header entries, not one — the builder appends, and REST Assured sends both. The two exceptions are the ones you reach for through `setContentType` and `setAccept` anyway: `content-type` and `accept` are the header names REST Assured overwrites by default. ## The comparison in one table | Prefix | Backing shape | Second call with the same name | Examples | |---|---|---|---| | `setX` | one field | replaces the first value | `setBaseUri`, `setPort`, `setAuth` | | `addX` | list or map | keeps both entries | `addHeader`, `addCookie`, `addFilter` | | `removeX` | list or map | drops the named entry | `removeParam`, `removeQueryParam` | ## What the surface deliberately omits The builder is asymmetric, and the asymmetry is worth knowing before you plan a template: 1. There is **no** `setHeader`, `setCookie` or `setFilter`. If you want exactly one header of a given name in the template, add it exactly once. 2. Removal exists **only for parameters** — `removeParam`, `removeQueryParam`, `removeFormParam`, `removePathParam`. There is no `removeHeader`, `removeCookie` or `removeFilter`. 3. So a template that must *not* carry something has to be built without it. You cannot subtract a header, a cookie or a filter after the fact; you build a second, narrower template instead. That third point is the practical consequence. A team that builds one maximal specification and expects individual cases to strip pieces off it will find the header and filter parts unstrippable, and will end up with tests that quietly send more than they meant to. ## The plural and Map forms follow the same rule Several `addX` methods come in bulk shapes — `addHeaders(Map<String, String>)`, `addCookies(Map)`, `addParams(Map)`, `addQueryParams(Map)`, `addFormParams(Map)`, `addPathParams(Map)` and `addFilters(List<Filter>)`. They are still `addX`, so they still append; handing a map to `addHeaders` does not replace the headers already collected, it merges the map's entries in beside them. Nothing in the builder takes a collection and swaps out what was there before, which is the same fact stated a second way: the collection half of a specification only ever grows while the builder is alive. ## Reading the prefix as documentation Two habits follow. First, when you review spec-building code, read the prefixes before the arguments: a `setX` repeated is dead code, an `addX` repeated is probably a duplicate on the wire, and both look identical at a glance. Second, when you extend a template, prefer adding a narrow second specification and composing it with `addRequestSpecification` over piling more `addX` calls onto a shared one — composition is reversible in the sense that you can choose not to compose, while an `addX` on the common template reaches every test in the suite at once. For a milk-round suite that means one base template with the host, prefix and content type, a small `depotHeadersSpec` for the routing headers, and a `loggingSpec` for the filters you only want in CI — each built by its own builder, each composed where it is wanted.

  • Why is there no setHeader on RequestSpecBuilder?
    Because headers on a request specification are a collection, not a single slot — a request can legitimately carry several entries with the same name. The builder exposes the collection operation it actually supports, `addHeader`, rather than a `setHeader` that would have to guess whether you meant replace-all or replace-this-name.
  • Which builder methods can undo something already added to the template?
    Only the parameter ones: `removeParam`, `removeQueryParam`, `removeFormParam` and `removePathParam`. Headers, cookies, multiparts and filters have no removal method, so anything you do not want in a template must be kept out of it — usually by building a second, narrower specification instead.

saying these in an interview costs you the question

  • Assumes addHeader replaces an existing header of the same name
  • Expects a removeHeader or removeFilter method to exist
  • Thinks the add/set prefixes are just naming taste
  • Believes calling setBasePath twice concatenates the two paths
  • Plans one maximal template that individual tests strip pieces off