What is the REST Assured library used for on the JVM, and how does its given/when/then request DSL work?
answer
- given = request, when = verb, then = assert
- body(GPath, Hamcrest matcher)
- static import RestAssured.* + Matchers.*
- needs a running server — it only speaks HTTP
- io.restassured (5.x) vs old com.jayway
basics
~20 sREST Assured is a Java library for testing HTTP/REST APIs. You write one fluent chain: given() sets up the request (headers, body, params, auth), when() fires the HTTP call (get/post/put/delete), then() asserts on the response (status, headers, body values).
solid answer
~40 sREST Assured is a JVM library that makes calling and asserting on a real HTTP API read almost like a sentence. The chain has three stages: - **given()** — request specification: base URI/path, headers, query and path params, cookies, auth, content type, request body (a String, a Map, or a POJO that gets serialized). - **when()** — the actual HTTP call: `get("/users/{id}", 42)`, `post("/users")`, etc. This performs a real network request against a running server. - **then()** — response validation: `statusCode(200)`, `contentType(JSON)`, `header(...)`, `body("name", equalTo("Ann"))` where the matcher is a Hamcrest matcher and the path is a GPath expression. You normally `import static io.restassured.RestAssured.*` and `org.hamcrest.Matchers.*`. `RestAssured.baseURI`/`port`/`basePath` set global defaults so tests don't repeat the host. Failures throw an `AssertionError` naming the expected vs actual value, so it plugs into any test runner.
code
java · 16 linesimport static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
given()
.baseUri("http://localhost:8080")
.contentType(io.restassured.http.ContentType.JSON)
.header("X-Trace-Id", "abc-123")
.body("{\"name\":\"ann\",\"email\":\"[email protected]\"}")
.when()
.post("/users")
.then()
.statusCode(201)
.contentType(io.restassured.http.ContentType.JSON)
.header("Location", notNullValue())
.body("name", equalTo("ann"));go deeper
Be able to write the three-stage chain from memory and explain what goes in each stage, plus the fact that a server must already be running.
Add the mechanics: verbs send the request, GPath + Hamcrest drive body assertions, POJOs are serialized by Jackson/Gson based on content type.
Talk about the static global config on RestAssured, when the chain belongs behind a reusable specification, and how failures are surfaced (log().ifValidationFails()).
Frame where an HTTP-level suite belongs in the overall testing strategy for the service and what the cost of owning one against a deployed environment really is.
## What REST Assured is REST Assured is a Java (JVM) library for **black-box testing HTTP APIs**. It is not a test runner and not a mocking framework — it is an HTTP client with a validation DSL bolted on. You point it at a running service (a locally started app, a container, a deployed environment), send a real request, and assert on the real response. Everything it does could be done with a raw HTTP client plus manual JSON parsing; the value is that it collapses "build request → send → parse body → assert" into one readable chain. ## The three stages The DSL is deliberately shaped like the Given/When/Then phrasing of behaviour specifications: **given()** returns a *request specification*. Everything you attach here describes the request before it is sent: - `baseUri(...)`, `port(...)`, `basePath(...)` - `header("X-Trace-Id", id)`, `headers(map)`, `cookie(...)` - `queryParam("page", 2)`, `pathParam("id", 42)`, `formParam(...)` - `contentType(ContentType.JSON)`, `accept(ContentType.JSON)` - `body(objectOrString)` — a String is sent as-is; a Map or POJO is serialized to JSON (Jackson/Gson on the classpath) or XML (JAXB) based on the content type - `auth().basic(...)`, `auth().oauth2(token)` **when()** is a readability no-op that returns the same specification; the *next* call is the verb, and that is what actually executes the request: `get`, `post`, `put`, `patch`, `delete`, `head`, `options`. Path templates are supported inline: `get("/users/{id}", 42)`. **then()** returns a *response specification* used for validation: - `statusCode(200)` or `statusCode(is(both(greaterThanOrEqualTo(200)).and(lessThan(300))))` - `contentType(ContentType.JSON)` - `header("Location", containsString("/users/"))` - `time(lessThan(2000L))` - `body("<gpath>", <hamcrest matcher>)` — the workhorse Each `body(...)` call takes a **GPath** expression (Groovy's path language, which for JSON looks like `user.address.city` and for arrays supports `items[0].id`, `items.size()`, `items.name`) and a **Hamcrest matcher** (`equalTo`, `hasItems`, `notNullValue`, `containsInAnyOrder`, …). This is why REST Assured pulls in Hamcrest and Groovy transitively. Optionally the chain continues with `.extract()` to pull values back into Java, or `.and()` purely for readability. ## A minimal example ```java given() .baseUri("http://localhost:8080") .contentType(ContentType.JSON) .body(new CreateUser("ann")) .when() .post("/users") .then() .statusCode(201) .body("name", equalTo("ann")); ``` ## Static imports and global config The DSL is designed around `import static io.restassured.RestAssured.*` (giving you `given()`, `when()`, `get()`) and `import static org.hamcrest.Matchers.*`. Static fields on `RestAssured` — `baseURI`, `port`, `basePath`, `defaultParser`, `filters(...)`, `requestSpecification`, `responseSpecification` — set suite-wide defaults. Because these are **static mutable globals**, they should be set once in suite setup and reset (`RestAssured.reset()`) rather than tweaked per test; per-test tweaking is a classic source of cross-test interference and problems under parallel execution. ## What it does not do - It does **not** start your application. Something else must have the server listening — the test framework's server-start support, a container, or a deployed environment. REST Assured only speaks HTTP to it. - It does **not** replace unit-level testing of internal classes; it exercises the API surface end to end, including serialization, routing, filters, and security. - Assertions produce `AssertionError`, so any JVM test runner reports them normally; REST Assured has no lifecycle of its own. ## Failure output When a `body(...)` assertion fails, the error message shows the GPath, the expected matcher description and the actual value. It does *not* dump the whole response by default — you add `log().ifValidationFails()` on the request and/or response side for that, which is essential for diagnosing failures in CI where you cannot rerun interactively. ## Packaging and versions The modern coordinates are `io.rest-assured:rest-assured` with the package `io.restassured` (5.x, Java 8+). Very old code uses `com.jayway.restassured` (2.x) — the package rename is a common upgrade stumbling block. Companion modules exist for extras: `json-schema-validator` (JSON Schema assertions), `xml-path`/`json-path` (standalone path parsing), and Kotlin/Scala extension modules.
- Does when() actually send the request?No. `when()` is a readability method that returns the same request specification. The HTTP call is made by the verb method that follows it — `get`, `post`, `put`, `patch`, `delete`, `head` or `options`. You can legally write `given()...get("/users")` with no `when()` at all; the stage exists purely so the chain reads like a specification.
- Where do the matchers in body("name", equalTo("ann")) come from, and where does the "name" expression come from?The matcher is a Hamcrest `Matcher`, so anything Hamcrest offers works — `equalTo`, `hasItems`, `containsString`, `greaterThan`, plus composed matchers. The path string is a GPath expression evaluated by Groovy against the parsed body, which is why nested access reads as `user.address.city` and collection operations like `items.size()` or `items.findAll { it.active }` are available.
- Does REST Assured start your application for you?No. It is only an HTTP client with assertions, so a server must already be listening at the configured base URI and port — started by the surrounding test setup, a container, or a deployed environment. If nothing is listening you get a connection-refused exception, not a failed assertion.
It is like dictating a request to an assistant: 'given these headers and this body, when you POST it, then check the receipt says 201 and the name is ann.'
saying these in an interview costs you the question
- Claiming when() is what performs the HTTP call, rather than the verb method after it.
- Thinking REST Assured starts or embeds the application under test.
- Believing the body() path is JSONPath ($.user.name) — it is GPath, so it is user.name with no leading $.
- Setting RestAssured.baseURI/port inside individual tests and never resetting, then blaming flakiness on the library.
- Saying it only works for JSON — it also handles XML, form and multipart payloads.