skip to content

In REST Assured, what does given().sessionId("abc123") actually put on the request?

level: middleimportance: should knowfreq 45%

answer

  1. name from config, value from you
  2. not the same rule as cookie()
  3. replace, do not append
  4. setting it twice keeps the second
  5. two-arg form names the cookie itself

basics

~20 s

It adds a cookie whose name comes from SessionConfig.sessionIdName(), JSESSIONID unless you changed it, carrying the value abc123. Unlike cookie(), it replaces any cookie already on the spec with that name rather than adding a second one.

solid answer

~50 s

The one-argument `RequestSpecification.sessionId(value)` resolves the cookie name from the active `SessionConfig` — `SessionConfig.DEFAULT_SESSION_ID_NAME`, the literal `JSESSIONID`, when nothing is configured — and delegates to the two-argument `sessionId(name, value)`. That method is where the interesting behaviour lives: if the spec already holds a cookie with that name it drops it and adds the new one, so `given().sessionId("a").sessionId("b")` sends only `b`. Plain `given().cookie("JSESSIONID", ...)` accumulates instead, so calling it twice puts two cookies on the `Cookie` header. That replace-not-append rule is also why an explicit `sessionId(...)` on a `GET /hives/h-42/telemetry` call beats `RestAssured.sessionId` and a `SessionFilter`: both of those step aside when the cookie name is already taken. There is also a two-argument form you can call directly, `given().sessionId("APIARY_SESSION", value)`, which names the cookie for that request only and does not change what `Response.sessionId()` reads back afterwards.

code

java · 34 lines
java
import io.restassured.config.SessionConfig;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.config;
import static io.restassured.RestAssured.given;
import static io.restassured.config.RestAssuredConfig.newConfig;

class HiveSessionIdShapeTest {

    @Test
    void secondSessionIdCallReplacesTheFirst() {
        given()
            .baseUri("https://hives.example.test")
            .sessionId("stale-hive-session")
            .sessionId("fresh-hive-session")
            .log().cookies()
        .when()
            .get("/hives/h-42/telemetry")
        .then()
            .statusCode(200);
    }

    @Test
    void twoArgFormNamesTheCookieForThisRequestOnly() {
        given()
            .baseUri("https://hives.example.test")
            .config(newConfig().sessionConfig(new SessionConfig().sessionIdName("APIARY_SESSION")))
            .sessionId("APIARY_SESSION", "fresh-hive-session")
        .when()
            .get("/hives/h-42/broods")
        .then()
            .statusCode(200);
    }
}

go deeper

for a junior

Know that the value becomes a cookie on the request and that JSESSIONID is the default name. Being able to write given().sessionId(value) and say where the value came from is the bar here.

for a middle

Explain the name lookup through SessionConfig and the replace-not-append rule, and be able to predict what given().sessionId(a).sessionId(b) puts on the Cookie header.

for a senior

Use the replace rule deliberately: pin a stale id to assert a 401 even when a SessionFilter or a global session id is in play, and know why those two stand down.

for a principal

Weigh whether session values belong inline in tests at all, or in a shared spec built per role, and what each choice does to how readable a failing test is.

## The one-argument form is a lookup plus a delegation `given().sessionId("abc123")` does two things. First it asks the request's configuration for the session id name: `config.getSessionConfig().sessionIdName()`, falling back to `SessionConfig.DEFAULT_SESSION_ID_NAME` — the literal string `JSESSIONID` — when no config has been attached yet. Then it calls the two-argument `sessionId(String sessionIdName, String sessionIdValue)` with that name. So the value never travels as anything special. It ends up as an ordinary cookie on the request spec, and REST Assured joins the spec's cookies into a single `Cookie` header when it builds the call. There is no session type, no server handshake, no `Authorization` header involved. ## Replace, not append — the part people get wrong The two-argument form checks whether the spec already carries a cookie with that name, matched case-insensitively. If it does, the method rebuilds the cookie list from every cookie **except** that one and then adds the new value. If it does not, it simply adds the cookie. That is a genuinely different rule from `RequestSpecification.cookie(name, value)`, which always appends. The consequences are easy to demonstrate against a beehive telemetry API: - `given().sessionId("a").sessionId("b")` sends one cookie, `JSESSIONID=b`. - `given().cookie("JSESSIONID", "a").cookie("JSESSIONID", "b")` sends two, `JSESSIONID=a; JSESSIONID=b`, and what the server does with that is its own business. - `given().cookie("JSESSIONID", "a").sessionId("b")` sends one, `JSESSIONID=b` — the `sessionId` call evicted the earlier cookie. - `given().sessionId("a").cookie("JSESSIONID", "b")` sends two, because the append rule belongs to `cookie(...)` and it does not care what is already there. The library's own integration suite pins this: a test named after the fact that setting the session id twice overwrites the first one asserts a distinct status line, which only happens if exactly one value arrives. ## The two-argument form overrides the configured name `given().sessionId("APIARY_SESSION", "abc123")` names the cookie for this request only. It does not mutate `SessionConfig`, and it does not change what `Response.sessionId()` will read off the response afterwards — that side is still driven by the configured name. If your beehive telemetry API names its session cookie `APIARY_SESSION` and you want both the send side and the read side to agree, configure it once instead: ```java RestAssured.config = RestAssured.config() .sessionConfig(new SessionConfig().sessionIdName("APIARY_SESSION")); ``` ## Why this makes the DSL win over everything else REST Assured has three places a session id can come from, and they are applied at different moments: | source | applied when | overwrites an existing cookie of that name? | | --- | --- | --- | | `given().sessionId(...)` | as you build the spec | **yes** — it evicts and replaces | | `SessionFilter` | in the filter chain, before the send | no — it skips if the name is taken | | `SessionConfig.sessionIdValue` (where `RestAssured.sessionId` lands) | inside the send step, last | no — it skips if the name is taken | Because the DSL call runs first and is the only one that replaces, an explicit `sessionId(...)` wins outright. That is what lets a negative test pin a deliberately stale id: ```java given() .sessionId("expired-hive-session") .when() .get("/hives/h-42/telemetry") .then() .statusCode(401); ``` even with a `SessionFilter` attached that holds a perfectly good id, and even with `RestAssured.sessionId` set globally. Both of those check first and stand down. ## Where the value goes in a reusable spec `RequestSpecBuilder` mirrors both forms as `setSessionId(String)` and `setSessionId(String, String)`, and each one just calls through to the same spec methods. So a shared spec built for a beekeeper role carries the cookie the same way an inline `given().sessionId(...)` does: ```java RequestSpecification keeperSpec = new RequestSpecBuilder() .setBaseUri("https://hives.example.test") .setSessionId(hiveSession) .build(); ``` ## What to check when the value does not arrive 1. **Is the configured name the one the server uses?** A mismatch means you are sending a cookie the server ignores, and reading back `null` from `Response.sessionId()`. 2. **Did something append a second cookie of the same name?** Mixing `cookie(...)` and `sessionId(...)` in one chain can do that, depending on the order. 3. **Is the value actually a session, or an empty string?** `sessionId(name, value)` rejects a `null` value outright, but it will happily send a blank one you assembled by accident. The cheapest confirmation is `given().log().cookies()` on the outgoing request: what the header carries is exactly what the spec's cookie list held at send time, with no further interpretation.

  • Is given().sessionId(id) really just a shortcut for given().cookie("JSESSIONID", id)?
    Almost. Both put one cookie on the request, but `cookie(...)` appends unconditionally while `sessionId(...)` evicts any same-named cookie first. It also reads the name from `SessionConfig` rather than hard-coding `JSESSIONID`, so a configured name is honoured automatically.
  • Does the two-argument sessionId(name, value) change what Response.sessionId() reads back?
    No. The two-argument form only names the cookie on that outgoing request. The read side is stamped from `SessionConfig.sessionIdName()` at request time, so if you want both directions to agree on a non-default name, configure `SessionConfig` rather than passing the name per call.

saying these in an interview costs you the question

  • Saying sessionId() and cookie() behave identically in every respect
  • Expecting two sessionId() calls to send two cookies
  • Thinking the session id travels as an Authorization header
  • Believing the two-arg form permanently changes the configured name
  • Assuming JSESSIONID is hard-coded and cannot be configured