skip to content

Canned Response Checks

Packaging the checks every response must pass - status, content type, headers, response time, body paths - into one object. Asked because these expectations add to a call's own, never replace them.

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

questions

3

In REST Assured, what does a ResponseSpecBuilder let you expect on every response?

level: juniorimportance: should knowfreq 48%

answer

  1. one object, every response's checks
  2. every method begins with expect
  3. status, type, headers, cookies, time, body
  4. build() returns a ResponseSpecification

basics

~20 s

ResponseSpecBuilder collects the checks every response must pass — status code, status line, content type, headers, cookies, response time and body paths — and build() returns one ResponseSpecification. It describes expectations only; a real response satisfies them later.

solid answer

~40 s

`ResponseSpecBuilder`, in `io.restassured.builder`, is the response-side builder. You chain `expectStatusCode(200)`, `expectStatusLine(...)`, `expectContentType(ContentType.JSON)`, `expectHeader("X-Quota-Period", "2026-Q3")` or `expectHeaders(Map)`, `expectCookie("QUOTA_SESSION")` or `expectCookies(Map)`, `expectResponseTime(lessThan(1500L))` and `expectBody("quotaRemainingKg", greaterThan(0))`, then call `build()` for a `ResponseSpecification`. Three further calls change how the response is read rather than what it must contain: `log(LogDetail)`, `registerParser(contentType, Parser)` and `setDefaultParser(Parser)`. Every method starts with `expect` because the object sits on the validate side of the DSL; the request-side `RequestSpecBuilder` uses `set` and `add` instead. On a fishing-quota API I keep one spec holding 200, `application/json` and a latency ceiling, and leave `quotaRemainingKg` assertions in the individual tests. Attached to a call, the spec's checks run in addition to the ones that call states for itself. The builder never sends anything and holds no response; it is a description that a later response is measured against.

code

java · 15 lines
java
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.specification.ResponseSpecification;

import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.lessThan;

ResponseSpecification quotaReadOk = new ResponseSpecBuilder()
        .expectStatusCode(200)
        .expectContentType(ContentType.JSON)
        .expectHeader("X-Quota-Period", "2026-Q3")
        .expectCookie("QUOTA_SESSION")
        .expectResponseTime(lessThan(1500L))
        .expectBody("quotaRemainingKg", greaterThan(0))
        .build();

go deeper

for a junior

Be ready to write one line of it from memory: new ResponseSpecBuilder().expectStatusCode(200).expectContentType(ContentType.JSON).build(). Knowing that every method starts with expect, and that build() hands back a ResponseSpecification, is enough at this stage.

for a middle

Explain the whole surface without a cheat sheet — status code, status line, content type, headers, cookies, response time, body paths — and say why expectResponseTime defaults to milliseconds and why no overload compares a literal body.

for a senior

Show judgment about what belongs in a shared spec. Anything true of every response from the service goes in; an assertion about one endpoint's payload does not, because it makes a failure point at a file the failing test never mentions.

for a principal

Own the question of how many response specs a suite should have. One per service reads as a contract; one per endpoint is duplication with extra indirection, and a spec nobody can name is a spec nobody maintains.

## What a response specification actually is A **response specification** is an `io.restassured.specification.ResponseSpecification`: a bag of expectations a response must satisfy, held apart from any single call. `ResponseSpecBuilder`, in `io.restassured.builder`, is the fluent way to fill that bag. You build one — typically in a small factory that the suite shares — and attach it to as many calls as you like; the checks it carries run **in addition to** the ones a call states for itself, they do not replace them. The builder never sends anything and never holds a response of its own. It is a description that some later response is measured against. The naming is the tell. Every expectation method starts with `expect`, because the object being filled sits on the **validate** side of the DSL. The request-side builder, `RequestSpecBuilder`, uses `set` and `add` prefixes instead. Reaching for `setBaseUri` on a `ResponseSpecBuilder` means you have the wrong builder in your hand. ## The expectation surface | What you want to pin down | `ResponseSpecBuilder` call | |---|---| | Status code | `expectStatusCode(int)` or `expectStatusCode(Matcher<Integer>)` | | Status line | `expectStatusLine(String)` or `expectStatusLine(Matcher<String>)` | | Media type | `expectContentType(ContentType)` or `expectContentType(String)` | | One header | `expectHeader(String, String)` or `expectHeader(String, Matcher<String>)` | | Many headers at once | `expectHeaders(Map<String, Object>)` | | A cookie | `expectCookie(name)`, `expectCookie(name, value)`, `expectCookie(name, Matcher<String>)`, `expectCookie(name, DetailedCookieMatcher)` | | Many cookies at once | `expectCookies(Map<String, Object>)` | | Latency ceiling | `expectResponseTime(Matcher<Long>)`, or the overload taking a `TimeUnit` | | A value in the body | `expectBody(Matcher<?>)` or `expectBody(String path, Matcher<?>)` | Two things follow from that table. `expectResponseTime(Matcher<Long>)` measures in **milliseconds** unless you pass a `TimeUnit`, so `lessThan(2L)` with no unit means two milliseconds. And there is no `expectBody(String)` overload that compares a literal payload — the body forms all take a matcher, and the optional first argument is a path into the body, not an expected value. ## Three settings that are not expectations The builder also carries three things that change how the response is *read* rather than what it must contain: - `log(LogDetail)` — the response is printed at that detail level whenever the spec is used. - `registerParser(String contentType, Parser)` — tells the spec that a vendor media type such as `application/vnd.quota.v2+json` should be parsed as JSON. - `setDefaultParser(Parser)` — the fallback used when the response declares no usable content type. Unlike `RequestSpecBuilder` there is no `setConfig` here; the builder picks up whatever `RestAssured.config` refers to at the moment you construct it. ## Building one for a fishing-quota API 1. Decide what is true of *every* response from the service — for the fishing-quota logger that is `200`, `application/json` and a latency ceiling. 2. Put exactly those in one spec and give it a name that says so, such as `quotaReadOk`. 3. Call `build()` to get the `ResponseSpecification` the tests will share. 4. Leave the endpoint-specific assertions — `quotaRemainingKg`, `vesselId`, `species` — in the individual tests, where a reader sees them next to the call. A common mistake is to push everything into the shared spec. A spec that asserts `quotaRemainingKg` belongs to exactly one endpoint and has stopped being shared setup; worse, when it fails, the failure message points at a spec in a different file from the test that failed. ## What the builder does not do - It does not describe the request. Base URI, headers to send, auth and request body all belong to `RequestSpecBuilder`. - It does not run anything at `build()` time; the expectations are evaluated only when a response is validated against the spec. - It does not narrow a call's checks. Everything in the spec is checked *as well as* whatever the call asserts itself. - It does not supply matchers. `greaterThan`, `equalTo` and the rest come from Hamcrest; the builder is only the seam that accepts them. ## Why teams reach for it The value is not typing saved — it is that "what a healthy response from this service looks like" becomes a single named object. When the fishing-quota API starts stamping an `X-Quota-Period` header on every response, you add one `expectHeader` line and every test using the spec starts checking it. There is a diagnostic payoff too: when a test fails on the spec, the failure is about the service's contract; when it fails on its own line, it is about that one endpoint. That separation is most of the reason to have the builder at all, and it is why a spec crammed with endpoint detail is worse than no spec.

  • Can a ResponseSpecBuilder expectation be a Hamcrest matcher rather than a literal value?
    Yes — every expectation has a matcher overload: `expectStatusCode(Matcher<Integer>)`, `expectStatusLine(Matcher<String>)`, `expectHeader(String, Matcher<String>)`, `expectCookie(String, Matcher<String>)` and `expectResponseTime(Matcher<Long>)`. The body forms take a matcher only; there is no overload comparing a literal payload. REST Assured supplies the seam, and the matchers themselves come from Hamcrest.
  • What unit does expectResponseTime use when you do not pass a TimeUnit?
    Milliseconds. The single-argument `expectResponseTime(Matcher<Long>)` delegates to the specification's time check with `TimeUnit.MILLISECONDS`; a second overload takes an explicit `TimeUnit`. So `lessThan(1500L)` is a 1.5-second ceiling for a fishing-quota read, and `lessThan(2L)` is two milliseconds — almost never what the author meant.

It is the pre-printed inspection form stapled to every landing record: the same boxes appear on all of them, and each catch fills them in.

saying these in an interview costs you the question

  • Thinks a ResponseSpecBuilder can also set the request's base URI
  • Believes build() runs the checks immediately
  • Says a response spec replaces the call's own then() assertions
  • Expects an expectBody overload that compares a whole JSON string
  • Confuses expectHeader with the request-side addHeader
open as a page

In REST Assured's ResponseSpecBuilder, which expectations stack and which replace an earlier call?

level: middleimportance: should knowfreq 36%

basics

~20 s

A REST Assured ResponseSpecBuilder accumulates body, header and cookie expectations, so repeated calls all run. Status code, status line, content type, response time and log detail are single fields: a second call silently replaces the first. There is no warning.

open as a page

A REST Assured ResponseSpecBuilder loses its expectStatusCode(200) after addResponseSpecification(...) — why?

level: seniorimportance: should knowfreq 27%

basics

~20 s

ResponseSpecBuilder.addResponseSpecification runs the response-side merge, which assigns the incoming spec's scalar fields unconditionally. Because that spec never set a status code, its null value is written over your 200. Only body, header and cookie assertions accumulate.

open as a page