skip to content

In REST Assured, where do withArgs(...) and withNoArgs() live, and what do they fill in?

level: middleimportance: should knowfreq 38%

answer

  1. statics on RestAssured, not on the response
  2. they return a List of Argument
  3. merge root and key, then String.format
  4. placeholder can live in the prefix
  5. withNoArgs needs a non-empty root path

basics

~20 s

withArgs and withNoArgs are static methods on io.restassured.RestAssured that return a List of Argument. You pass them into body, rootPath or appendRootPath, which fills the placeholders in the merged path with String.format. They are not methods on the response.

solid answer

~50 s

`RestAssured.withArgs(Object first, Object... more)` and `RestAssured.withNoArgs()` are **statics on `io.restassured.RestAssured`**, not calls on the validatable response, and both return a `List<Argument>`. You hand that list to an overload that accepts it: `body(String path, List<Argument>, Matcher, Object...)`, `body(List<Argument>, Matcher, Object...)`, `rootPath(String, List<Argument>)` or `appendRootPath(String, List<Argument>)`. REST Assured first merges the root path with the key, then runs `String.format` over the merged result, so a `%d` can live in the prefix and be supplied by an argument on the `body(...)` call — `rootPath("lots[%d]")` plus `body("breed", withArgs(0), equalTo("Angus"))` asserts `lots[0].breed`. `withNoArgs()` returns an empty list and is for the case where the prefix already carries every value, so the expectation targets the prefix itself; that no-key overload requires a non-empty root path and throws `IllegalStateException` otherwise. Supply fewer arguments than the merged path has placeholders and REST Assured pads the list rather than throwing, leaving a literal `%s` in the path.

code

java · 13 lines
java
import static io.restassured.RestAssured.when;
import static io.restassured.RestAssured.withArgs;
import static io.restassured.RestAssured.withNoArgs;
import static org.hamcrest.Matchers.equalTo;

when().get("/sales/SALE-77/lots")
.then()
    .rootPath("lots[%d]")
    .body("breed", withArgs(0), equalTo("Angus"))
    .body("breed", withArgs(1), equalTo("Hereford"))
    .body("headCount", withArgs(0), equalTo(24))
    .rootPath("lots[%d].currentBid.amount", withArgs(0))
    .body(withNoArgs(), equalTo(1875));

go deeper

for a junior

Recognise withArgs in a chain and know it is statically imported from RestAssured, so a body(...) call can reuse one prefix with a different index.

for a middle

Explain that the root path and key are merged first and formatted second, which is why a placeholder in the prefix can be filled from a later body(...) call.

for a senior

Know the failure shapes: IllegalStateException from the keyless overload with no prefix, and a surviving literal %s when you supply too few arguments. Both look like path bugs at first glance.

for a principal

Set the boundary on how much of a path may be parameterised. A path assembled from variable parts is compiled as Groovy, so a convention that keeps the varying portion to indices and known field names is a safety rule, not a style one.

Path arguments are REST Assured's answer to a path string that is nearly identical across several expectations. The mechanism is small, and almost every mistake with it comes from misplacing where the two helper methods live. ## They are statics on `RestAssured`, not response methods `withArgs(Object firstArgument, Object... additionalArguments)` and `withNoArgs()` are declared on `io.restassured.RestAssured` and are meant to be statically imported. Each returns an unmodifiable `List<Argument>`: - `withArgs(0)` produces a one-element list. - `withArgs("headCount", 2)` produces a two-element list, in order. - `withArgs(null)` is rejected outright — the first argument is validated as non-null with the message that you need to supply at least one argument. - `withNoArgs()` produces an empty list. They are **passed into** an assertion, never chained off one. There is no `then().withArgs(...)`, and looking for one is the usual first wrong turn. ## The overloads that accept them Four places on the assertion side take a `List<Argument>`: | Call | What the arguments fill | |---|---| | `body(String path, List<Argument>, Matcher, Object...)` | placeholders in the merged root plus key | | `body(List<Argument>, Matcher, Object...)` | placeholders in the root path, with no key | | `rootPath(String, List<Argument>)` | placeholders in the prefix as it is set | | `appendRootPath(String, List<Argument>)` | placeholders in the fragment being appended | ## Merge first, then format The order matters and is easy to get backwards. REST Assured merges the current root path with the key you supplied, and only then applies the arguments to that merged string with `String.format`. Two consequences follow: 1. A placeholder may live in the prefix and be filled by a `withArgs(...)` written on a later `body(...)` call. Against a cattle-auction sale listing, `rootPath("lots[%d]")` followed by `body("breed", withArgs(0), equalTo("Angus"))` and `body("breed", withArgs(1), equalTo("Hereford"))` asserts `lots[0].breed` and `lots[1].breed` with one prefix. 2. Placeholders in the prefix and in the key are filled from the same list, left to right, because by then they are one string. The syntax is plain Java formatting, so `%s` and `%d` both work and behave as `String.format` defines them. If the merged path contains more `%s` placeholders than you supplied arguments for, REST Assured pads the list with literal `%s` values rather than throwing, so the surplus placeholders survive into the path unchanged — which normally surfaces later as a path that does not resolve. ## `withNoArgs()` and the keyless overload `body(List<Argument>, Matcher, Object...)` takes no path at all. It asserts against the root path itself, which is why it only makes sense once the prefix already names a value. It has one hard precondition: the root path must be non-empty, or REST Assured throws `IllegalStateException` complaining that arguments cannot be specified when the root path is empty. `withNoArgs()` is how you invoke that overload when the prefix already contains every value it needs: - `rootPath("lots[%d].currentBid.amount", withArgs(0))` resolves the prefix to `lots[0].currentBid.amount` immediately, at the moment `rootPath` is called. - `body(withNoArgs(), equalTo(1875))` then asserts on exactly that resolved prefix, adding nothing. Use it where the alternative would be repeating a long resolved prefix as a key. ## Why not just build the string yourself Java string concatenation would produce the same path, so the argument for `withArgs` is readability and safety rather than capability: - The prefix stays written once, in one place, instead of being rebuilt per expectation. - The values appear at the point of the assertion, which is where a reader looks for them. - The path expression is compiled and evaluated as Groovy, so building it by concatenating values that came from outside the test is a genuine injection hazard. Keeping the shape fixed and passing indices and known field names through `withArgs` keeps the variable part small and inspectable. ## The mistakes worth naming - Reaching for `withArgs` as a method on the response instead of a static import from `RestAssured`. - Using `body(withNoArgs(), matcher)` with no root path set, and getting `IllegalStateException` rather than a path error. - Assuming arguments apply to the key only, then being surprised when a `%d` in the prefix consumes the first one. - Supplying fewer arguments than placeholders and getting a path containing a literal `%s` instead of an exception. Used sparingly — an index over a list of lots, one field name that varies — path arguments keep a repetitive block of expectations short without hiding what each line asserts.

  • Can a placeholder in the root path be filled by an argument passed on a later body(...) call?
    Yes, and that is the main reason the feature exists. REST Assured merges the prefix with the key before formatting, so a `%d` in the prefix and a `%s` in the key draw from the same argument list, left to right, in the order you supplied them.
  • Why does body(withNoArgs(), equalTo(1875)) sometimes throw IllegalStateException?
    That keyless overload asserts against the root path itself, so it is meaningless without one. If no prefix is set, REST Assured throws immediately, saying arguments cannot be specified when the root path is empty. Set a `rootPath(...)` first, or use the ordinary `body(path, matcher)` form.

saying these in an interview costs you the question

  • Looks for withArgs as a method on the validatable response
  • Thinks arguments fill placeholders in the key only
  • Expects a missing argument to throw rather than leave a literal placeholder
  • Uses withNoArgs with no root path set
  • Builds the path by concatenating untrusted values instead of using placeholders