skip to content

Path Placeholders

Filling the curly-brace slots in a request path: named values, the index-based positional form, what the library does when the two disagree, and whether a slash or a space in a value gets escaped.

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

questions

5

In REST Assured, which placeholder does a positional path value fill when a named one is already set?

level: middleimportance: must knowfreq 55%

answer

  1. two passes, not one
  2. named lookup happens first
  3. index runs over what is left
  4. one extra name re-aims every argument

basics

~20 s

REST Assured applies named path parameters first, so a positional value fills the first placeholder still undefined, not the first placeholder in the path. Adding a named parameter upstream therefore shifts what every trailing argument in that call means.

solid answer

~40 s

REST Assured resolves a template in two passes. It first looks up each `{name}` among the **named** path parameters set with `pathParam` or `pathParams`; only the placeholders that find no match are offered to the **unnamed**, index-based values passed as trailing arguments, and those are consumed in order. So `given().pathParam("signatureNo", 12).when().get("/orders/{orderId}/signatures/{signatureNo}", "BND-4417")` sends `/orders/BND-4417/signatures/12` — the one trailing value went to `{orderId}`, the *second* placeholder, because the first was already spoken for. Position is relative to what is left, not to the template. The practical consequence is that adding a single `pathParam` to shared setup silently re-aims every positional argument in the calls that use it, which is why suites that mix the forms tend to end up naming everything. A named value also covers each occurrence of a placeholder that the template repeats.

code

java · 12 lines
java
import static io.restassured.RestAssured.given;

// The named value claims {signatureNo} in the first pass...
given()
    .pathParam("signatureNo", 12)
.when()
    // ...so the single trailing value fills {orderId}, the second slot
    .get("/orders/{orderId}/signatures/{signatureNo}", "BND-4417")
.then()
    .statusCode(200);

// sent: /orders/BND-4417/signatures/12

go deeper

for a junior

Know that both forms exist and can appear on the same request. If you see a pathParam plus a trailing argument, do not assume the argument fills the first slot in the path.

for a middle

Be able to state the two-pass rule and walk a mixed example placeholder by placeholder, saying for each one whether the value came from the named map or from the next positional argument.

for a senior

Show how this fails in a suite: a helper that gains one path parameter re-aims positional arguments everywhere downstream, and the symptom is a wrong URL rather than a compile error.

for a principal

Own the standard. Decide whether mixing named and positional path values is allowed at all, and how the review or lint story enforces it once a hundred tests share the same request setup.

## The two passes REST Assured makes over a template When a request is sent, REST Assured walks the path template segment by segment looking for `{` ... `}` pairs. For each placeholder it finds, it does two things in a fixed order: 1. Look the placeholder's name up among the **named** path parameters — everything registered through `pathParam(name, value)`, `pathParams(name, value, ...)` or `pathParams(Map)`. 2. Only if that lookup comes back empty, take the **next unused unnamed value** — one of the trailing arguments handed to `get`, `post`, `put`, `delete` and friends. That ordering is the whole rule, and it is the source of nearly every surprise on this topic. Named parameters have precedence; the index-based values are a fallback that fills the gaps. ## What "index-based" actually indexes The intuitive reading — that the first trailing argument goes to the first `{...}` in the string — is wrong whenever a named parameter is also in play. The index runs over the placeholders **still undefined after the named pass**, not over the placeholders in the template. Two mirror cases on a bookbindery order API make it concrete, with the template `/orders/{orderId}/signatures/{signatureNo}`: - `given().pathParam("signatureNo", 12).when().get(template, "BND-4417")` sends `/orders/BND-4417/signatures/12`. The trailing value skipped past the named slot. - `given().pathParam("orderId", "BND-4417").when().get(template, 12)` sends the same URL. The trailing value landed in the *last* placeholder this time. In both cases exactly one value was passed positionally, and in both cases it went somewhere different — decided entirely by which name was already bound. ## A worked trace Take `/orders/{orderId}/signatures/{signatureNo}/cloth/{clothCode}` with `pathParam("signatureNo", 12)` set and the call `get(template, "BND-4417", "MOROCCO")`: | placeholder | named lookup | value used | source | |---|---|---|---| | `{orderId}` | miss | `BND-4417` | first unnamed | | `{signatureNo}` | hit | `12` | named | | `{clothCode}` | miss | `MOROCCO` | second unnamed | The resulting path is `/orders/BND-4417/signatures/12/cloth/MOROCCO`. Notice that the two unnamed values were consumed in their own order, but they straddled the named slot rather than being blocked by it. ## Why this bites in a real suite The failure mode is not usually a single confusing call; it is a change made somewhere else: - Someone adds `pathParam("orderId", ...)` to a helper that every bindery test funnels through. Every call that used to pass the order id positionally now sends that id into the *next* placeholder instead. - A template gains a segment. Positional call sites keep compiling and start filling the wrong slots. - A placeholder is renamed — `{signatureNo}` to `{signatureIndex}` — and the named binding quietly stops matching, so a positional value slides into a slot nobody intended. None of these are compile errors. Some of them fail loudly at send time with an `IllegalArgumentException` about the number of path parameters; the dangerous ones are the cases where the counts still balance and the request simply goes to the wrong URL, coming back as a puzzling 404 or, worse, a 200 for the wrong resource. ## Repeated placeholders behave differently in the two forms A template may name the same placeholder twice, as in `/orders/{orderId}/audit/{orderId}`: - With the named form, one `pathParam("orderId", "BND-4417")` fills both occurrences. The lookup is by name and it succeeds each time. - With the positional form, each occurrence is a separate gap and consumes the next trailing value, so the same template would need two arguments. This asymmetry is a small but genuine reason to prefer names once a path repeats an identifier. ## Keeping it out of your suite 1. Pick one form per call site and do not mix them in the same request unless you have a reason you can state out loud. 2. If shared setup contributes any path parameter at all, name every path parameter in the tests that use that setup — mixing is only safe when you can see both halves at once. 3. When you must mix, write the named parameter and the template next to each other so a reader can count the gaps without scrolling. 4. Treat a puzzling 404 in a path-parameterised test as a URL problem first: print the request URI before you go looking at the server. The rule to carry away is short: **named wins, and the unnamed values fill only what is left, in order.**

  • How would you prove which placeholder a value actually landed in, without a debugger?
    Print the request line before the call: `given().log().uri()` is on the request half of the log DSL and shows the fully built URI, placeholders resolved. In a suite you can enable it only for failures instead. Reading the URI settles the question in one run, which is far faster than reasoning about the ordering rule from the test source.
  • If mixing the two forms is this fragile, why does REST Assured support it at all?
    It lets a shared setup pin the parts of a path that never vary — a tenant or a bindery id — while each test supplies only the parts that do, positionally and briefly. That is a real convenience, and the cost is that the reader must see both halves to know where a value lands, which is exactly why many teams forbid the mix by convention.

Think of the placeholders as seats on a bench and the named parameters as reservations. Reservations are honoured first and walk-ins are seated, in order, into whatever is still empty — so one extra reservation quietly shifts where every walk-in ends up.

saying these in an interview costs you the question

  • Says the first trailing value always fills the first placeholder
  • Thinks a positional value overrides a named one for the same slot
  • Believes the two forms cannot be combined on one request
  • Assumes a wrongly aimed value always raises an exception
  • Expects a repeated placeholder to need two named values
open as a page

In REST Assured, what changes when you set given().urlEncodingEnabled(false) on a request?

level: middleimportance: must knowfreq 44%

basics

~20 s

Setting urlEncodingEnabled(false) switches REST Assured's automatic URL encoding off for that whole request, path placeholder values included. Whatever you supply then goes on the wire as typed, so you become responsible for encoding every value yourself. The default is on.

open as a page

In REST Assured, does a slash or a space inside a path-parameter value reach the server unescaped?

level: middleimportance: must knowfreq 51%

basics

~20 s

REST Assured percent-encodes each filled path segment by default, so a slash inside a value becomes %2F and a space becomes %20. The value cannot introduce an extra path segment, and other reserved characters are escaped as well.

open as a page

In REST Assured, how do you fill the {orderId} placeholder in a request path?

level: juniorimportance: should knowfreq 71%

basics

~20 s

REST Assured fills curly-brace path placeholders two ways. You name them on given with pathParam or pathParams, or pass values positionally as trailing arguments to the request method. Positional values fill the remaining placeholders left to right.

open as a page

A REST Assured call fails with IllegalArgumentException: Invalid number of path parameters — how do you diagnose it?

level: seniorimportance: should knowfreq 41%

basics

~20 s

REST Assured compares the placeholders it found in the path with the named and positional values supplied, and the exception message names both halves: redundant values with no placeholder, and undefined placeholders with no value. Read those two lists first.

open as a page