skip to content

Endpoint Targeting

How a call decides which URL it hits: the static host and path defaults, the per-request overrides that beat them, and the placeholders a path template fills in just before the request goes out.

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

explore

questions

9

In REST Assured, how do given().baseUri() and given().basePath() decide where a request lands?

level: juniorimportance: must knowfreq 72%

answer

  1. three pieces joined into one URL
  2. base URI, then base path, then verb path
  3. one slash inserted, doubles collapsed
  4. per-request call overwrites the static copy
  5. nothing set means localhost

basics

~20 s

REST Assured builds the target URL by joining baseUri, then basePath, then the path given to the verb. Exactly one slash is inserted between the parts. Both methods override the matching static field for that single request only.

solid answer

~50 s

`given().baseUri(...)` and `given().basePath(...)` set the two pieces that sit in front of the path you hand to a verb. On an allotment water-rota API, `given().baseUri("https://rota.allotment-water.test").basePath("/api/v2").get("/plots/17/slots")` targets `https://rota.allotment-water.test/api/v2/plots/17/slots`. REST Assured concatenates the base URI (including any path the base URI itself carries), then the base path, then the verb's path, normalising the seams: a missing slash is inserted and a doubled one collapsed. Both calls are per-request — they overwrite the values the specification copied from the static `RestAssured.baseURI` and `RestAssured.basePath` at `given()`, and nothing outside that chain sees the change. There is no merge and no precedence arithmetic: the last write to the specification's field is what the verb reads. With neither set, the base URI is `RestAssured.DEFAULT_URI`, the literal `http://localhost`, and the base path is empty. Reach for the per-request form when one call must leave the suite's usual target — a warden-portal health probe, say.

code

java · 22 lines
java
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;

// -> GET https://rota.allotment-water.test/api/v2/plots/17/slots
given()
    .baseUri("https://rota.allotment-water.test")
    .basePath("/api/v2")
.when()
    .get("/plots/17/slots")
.then()
    .statusCode(200)
    .body("plotId", equalTo(17));

// A base URI carrying its own prefix; the seams are normalised
// -> GET https://rota.allotment-water.test/gateway/api/v2/taps/3/bookings
given()
    .baseUri("https://rota.allotment-water.test/gateway/")
    .basePath("/api/v2")
.when()
    .get("taps/3/bookings")
.then()
    .statusCode(200);

go deeper

for a junior

Be ready to write the chain from memory and say out loud which URL it produces. Knowing that base URI plus base path plus verb path are concatenated, with slashes normalised, is the whole expected answer here.

for a middle

Explain the mechanics: the statics are copied into the specification when the chain starts, and the per-request call overwrites that copy rather than merging with it. Mention the empty base path and the localhost default.

for a senior

Show the operational angle — which piece you would make configurable, why the version prefix belongs in the base path rather than in every verb call, and how you would prove where a failing test actually sent its request.

for a principal

Own the convention: one place decides the host for a run, the API's own prefix lives in the base path, and per-request overrides are reserved for genuine exceptions rather than used as a substitute for a shared target.

REST Assured never holds a finished URL for a request. It holds three separate pieces and joins them at the moment a verb is called, so the address a test actually reaches is always the product of an assembly rule rather than a stored string. Knowing that rule is the difference between a suite you can repoint at another environment in one line and one that quietly hits the wrong host. ## The three pieces - **Base URI** — the scheme and authority, optionally carrying a path prefix of its own; set it with `given().baseUri("https://rota.allotment-water.test")`. - **Base path** — a path fragment shared by a family of calls; set it with `given().basePath("/api/v2")`. - **The verb path** — the string handed to `get(...)`, `post(...)`, `delete(...)` or `request(...)`, for example `"/plots/17/slots"`. Written against an allotment water-rota API, `given().baseUri("https://rota.allotment-water.test").basePath("/api/v2").when().get("/plots/17/slots")` sends a GET to `https://rota.allotment-water.test/api/v2/plots/17/slots`. ## How the join works REST Assured concatenates the pieces left to right and normalises every seam, so you never have to count slashes: 1. Start with the base URI's scheme and authority. 2. Append the path the base URI itself carries, if any — `https://rota.allotment-water.test/gateway` contributes `/gateway`. 3. Append the base path. 4. Append the verb path. At each seam a single slash is inserted when neither side supplies one, and a doubled slash is collapsed back to one. That is why `baseUri("http://localhost/")` with `get("/plots")` and `baseUri("http://localhost")` with `get("plots")` resolve to the same address. It also means a base URI that already carries a prefix and a base path **stack** rather than compete: `/gateway` plus `/api/v2` plus `/plots` yields `/gateway/api/v2/plots`. ## Per-request call versus the static field Both names exist twice — as a field on `io.restassured.RestAssured` and as a method on `RequestSpecification`. The relationship is copy-then-overwrite: | | `RestAssured.baseURI` / `RestAssured.basePath` | `given().baseUri(...)` / `given().basePath(...)` | |---|---|---| | Scope | every request built afterwards | only the chain you called it on | | When it is read | copied into the specification at `given()` | written onto that specification directly | | Effect on other tests | changes all of them | none | | Typical use | the suite's normal target | one call that must go somewhere else | Because the statics are copied into the specification when the chain is created, a per-request call simply overwrites the copy. There is no merge and no "most specific wins" arithmetic: the last write to the specification's field is what the verb reads. So `given().baseUri("https://warden.allotment-water.test").get("/plots")` in one test leaves every other test pointed wherever the suite normally points. That also means the two forms are not in competition and never need to be reconciled. A suite normally sets the target once, in whatever hook runs before the first test, and then writes plain relative paths everywhere; the per-request methods are for the handful of calls that must go somewhere else. Reading a chain top to bottom therefore tells you the whole answer: if it names a base URI, that is the target, and if it does not, the target is whatever the run was configured with. ## What you get when you set nothing - The base URI defaults to `RestAssured.DEFAULT_URI`, the literal string `http://localhost`. - The base path defaults to `RestAssured.DEFAULT_PATH`, the empty string. - A bare `get("/plots")` in a fresh JVM therefore targets `http://localhost:8080/plots`; the `8080` comes from a separate port rule that fires for a `localhost` authority. - Passing `null` to either method throws a `NullPointerException` naming `"Base URI"` or `"Base Path"` — there is no argument that unsets them again. That default is shaped for a service booted on the same machine as the test run. The moment a suite targets anything else, one of the two has to be set explicitly. ## Putting each piece in the right place - Put the **scheme, host and port** in the base URI: that is the part that differs between a laptop and a deployed environment. - Put the **version or gateway prefix** in the base path. `/api/v2` is a property of the API rather than of the environment, so it belongs where a target switch will not disturb it. - Put the **resource path** in the verb, so a reader scanning the test sees `/plots/17/slots` at the call site instead of buried in setup. - Keep that verb path **relative**. A path beginning with a scheme discards both defaults outright, and that is the most common reason a repointed suite still reaches the old host. The payoff is an address assembled from parts you can each change independently, every one of them visible in the chain that sends the request.

  • If the base URI already ends in a path segment, does the base path replace it?
    No — they stack. REST Assured keeps the path carried by the base URI, appends the base path after it, then appends the verb path. A base URI of `https://rota.allotment-water.test/gateway` with a base path of `/api/v2` and a verb path of `/plots` resolves to `/gateway/api/v2/plots`.
  • What does REST Assured target if you never set a base URI or base path at all?
    `RestAssured.DEFAULT_URI`, the string `http://localhost`, with an empty base path from `RestAssured.DEFAULT_PATH`. A bare `get("/plots")` then goes to `http://localhost:8080/plots`, because the port rule appends 8080 when the authority is exactly `localhost`. Nothing fails or warns; the request simply goes to a local address.

Think of a postal address: the base URI is the town, the base path is the street, and the verb path is the house number. Change the town and every letter still finds the same street and number.

saying these in an interview costs you the question

  • Thinks basePath is prepended to the host rather than to the path
  • Believes a base URI may not carry a path prefix of its own
  • Assumes given().baseUri() also changes RestAssured.baseURI for later tests
  • Adds slashes by hand and expects a doubled slash to survive
  • Thinks an unset base URI makes the request fail rather than target localhost
open as a page

In REST Assured, when does a request actually go to port 8080?

level: middleimportance: must knowfreq 56%

basics

~20 s

REST Assured appends its default port of 8080 only when the target carries no port and its authority is exactly localhost. An explicitly set port always wins over it, and an https target with no port set stays on 443.

open as a page

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

level: middleimportance: must knowfreq 55%

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.

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

Why does a REST Assured test still hit the old host after you set given().baseUri()?

level: seniorimportance: should knowfreq 44%

basics

~20 s

A fully qualified URL in the verb wins. When the path handed to get or request starts with a scheme, REST Assured drops baseUri and basePath and uses that URL's own authority and path. Only an explicit port still applies.

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

In REST Assured, what does given().request(Method, path) do that get() and post() cannot?

level: middleimportance: nice to knowfreq 29%

basics

~20 s

REST Assured's request method takes the HTTP verb as a value rather than as a method name: the eight Method enum constants, or any verb at all through the String overload. Path resolution against baseUri and basePath is unchanged.

open as a page