In REST Assured, why is there no then().log().params() or given().log().status()?
answer
- eight values, but not eight per side
- four shared, three request, one response
- PARAMS, METHOD, URI describe a request
- STATUS describes only a response
- wrong side throws IllegalArgumentException
basics
~20 sREST Assured's LogDetail is side-specific: PARAMS, METHOD and URI describe only a request, STATUS only a response. Each log spec declares only the calls its side can print, and the logging filters throw IllegalArgumentException when a wrong value reaches them.
solid answer
~50 s`LogDetail` has exactly eight values — `ALL`, `HEADERS`, `COOKIES`, `BODY`, `STATUS`, `PARAMS`, `METHOD` and `URI` — but no single side can print all eight. Four are shared: `ALL`, `HEADERS`, `COOKIES` and `BODY`. `PARAMS`, `METHOD` and `URI` describe something only a request has, so they appear on `RequestLogSpecification` alone as `params()`/`parameters()`, `method()` and `uri()`. `STATUS` describes only a response, so `status()` appears on the response log spec alone, beside `ifError()`, `ifStatusCodeIsEqualTo(int)` and `ifStatusCodeMatches(Matcher)`. The DSL enforces this by omission — `then().log().params()` is not a method — and the filters enforce it again at runtime: `RequestLoggingFilter` rejects `LogDetail.STATUS` and the response logging filters reject `PARAMS`, `METHOD` and `URI`, both with `IllegalArgumentException`. That second check matters because `LogDetail` can also be passed in programmatically. On a seed-bank call it means `given().log().uri()` and `then().log().status()`, never the other way round.
code
java · 14 linesimport static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.greaterThan;
given()
.log().method() // LogDetail.METHOD - request only
.log().params() // LogDetail.PARAMS - request only
.queryParam("vault", "V3")
.when()
.get("/seed-bank/accessions")
.then()
.log().status() // LogDetail.STATUS - response only
.log().headers() // LogDetail.HEADERS - both sides
.statusCode(200)
.body("accessions.size()", greaterThan(0));go deeper
Recall that LogDetail has eight values and that they are not interchangeable between the two sides. If you can name ALL, HEADERS, COOKIES and BODY as the shared four, you have the useful half of it.
Explain the mapping in both directions: which enum value each DSL call passes, and why the request spec has no status() while the response spec has no params(), method() or uri().
Point out that the enum is also passed programmatically, so the guard is a runtime IllegalArgumentException raised when the filter is constructed, not a compile error, and say where in a suite that would surface.
Frame it as an API design choice: one shared enum plus per-side validation, rather than two enums. Be ready to say what that buys and what it costs a caller who assembles log settings dynamically.
## One enum, two sides `io.restassured.filter.log.LogDetail` is the vocabulary REST Assured uses to say *how much* of a message to print. It declares exactly eight constants — `ALL`, `HEADERS`, `COOKIES`, `BODY`, `STATUS`, `PARAMS`, `METHOD` and `URI` — and both halves of the DSL draw from that one enum. What the enum does **not** do is make every value legal everywhere. A request has a method, a URI and parameters and no status of its own; a response has a status and no method, URI or parameters. The DSL and the logging filters both encode that asymmetry, in two different ways. ## The mapping, value by value | `LogDetail` | Side | DSL call | |---|---|---| | `ALL` | both | `log().all()`, `log().everything()` | | `HEADERS` | both | `log().headers()` | | `COOKIES` | both | `log().cookies()` | | `BODY` | both | `log().body()` | | `METHOD` | request only | `given().log().method()` | | `URI` | request only | `given().log().uri()` | | `PARAMS` | request only | `given().log().params()`, `given().log().parameters()` | | `STATUS` | response only | `then().log().status()` | Four shared, three request-only, one response-only. Note that `ALL` is not a fixed list of lines: it means "everything this side can print", so it resolves to method, URI, proxy, parameters, headers, cookies and body on a request, and to the status line, headers and body on a response. The response side carries three further calls — `ifError()`, `ifStatusCodeIsEqualTo(int)` and `ifStatusCodeMatches(Matcher)` — but those choose *when* to print rather than *what*, and each of them prints with `LogDetail.ALL`. ## The DSL enforces the split by omission The asymmetry is visible in the interfaces themselves, which is the cheapest possible enforcement: - `given().log()` returns a `RequestLogSpecification`, which adds `params()`, `parameters()`, `uri()` and `method()` on top of the shared set. - `then().log()` returns a `ValidatableResponseLogSpec`, which adds `status()`, `ifError()`, `ifStatusCodeIsEqualTo(int)` and `ifStatusCodeMatches(Matcher)` on top of the shared set. - Neither interface declares the other's four, so `then().log().params()` and `given().log().status()` do not compile — there is no runtime surprise to debug. - The shared six (`all`, `everything`, `body`, `headers`, `cookies`, `ifValidationFails`) come from a common `LogSpecification` contract that both sides honour. - `expect().log()`, and a `ResponseSpecification`'s own `log()`, return a `ResponseLogSpecification` — a different interface from the one `then().log()` returns, but with the same four response-only calls on top of the same shared set. ## The filters enforce it again, at runtime The DSL is not the only door into these values. `LogDetail` is a public enum and can be handed to a logging filter directly, so the check is repeated where the printing actually happens: 1. `RequestLoggingFilter`'s constructor rejects `LogDetail.STATUS` with an `IllegalArgumentException` reading *"STATUS is not a valid LogDetail for a request."* 2. The response-side logging filters reject `PARAMS`, `URI` and `METHOD` with the mirror-image message, *"... is not a valid LogDetail for a response."* 3. Both checks fire when the filter is **constructed**, not when the request runs, so the failure lands on the line that configured logging rather than deep inside a call. Nothing is silently dropped, and nothing is quietly widened to `ALL`. A wrong value is an error, not a hint. ## What each value actually prints Knowing the split is only half of it; the printer decides the shape of the output: - `METHOD` writes one line, `Request method: GET`. - `URI` writes one line, `Request URI:`, followed by the fully resolved URL including the query string. - `PARAMS` writes four labelled maps — request, query, form and path parameters — plus any multipart parts. - `STATUS` writes the response's status line, such as `HTTP/1.1 409 Conflict`, not the bare integer. - `ALL` on the request also emits a `Proxy:` line that no narrower value prints; `ALL` on the response is the status line, the headers and the body. ## Why it matters in a suite On a seed-bank inventory API the split maps cleanly onto what you are diagnosing. A search over `GET /seed-bank/accessions?vault=V3&taxon=Silene` is diagnosed by its parameters, so `given().log().params()` is the call that earns its place in the chain. A write to `POST /seed-bank/accessions` that starts returning `409` is diagnosed by `then().log().status()`, which tells you the outcome without dragging a whole inventory payload into the CI log. Reaching for the wrong side is the most common mistake on this surface, and because the compiler catches it the cost is only the minute spent wondering where the method went — provided you remember which four values belong to which half. The one case where the mistake escapes the compiler is a value chosen at runtime and handed to a logging filter directly: a helper that takes a `LogDetail` parameter and builds a filter from it will accept `LogDetail.URI` from a caller who meant it for a request and then fail when that helper is pointed at a response. Keeping the two halves separate in your own helper signatures — one for the request side, one for the response side — removes the whole class of error, and it costs nothing beyond a second method.
- Which LogDetail values does REST Assured accept on both sides of the DSL?`ALL`, `HEADERS`, `COOKIES` and `BODY`. `PARAMS`, `METHOD` and `URI` are request-only and `STATUS` is response-only. Note that `ALL` means "everything this side can print", so it resolves to a different set of lines on a request than on a response.
- What happens when a LogDetail value reaches the side that cannot print it?Construction fails with `IllegalArgumentException`. The request logging filter rejects `LogDetail.STATUS` with "STATUS is not a valid LogDetail for a request", and the response logging filters reject `PARAMS`, `URI` and `METHOD` with the mirror-image message. Nothing is silently ignored or widened.
It is the same asymmetry as a parcel and its delivery receipt: the address and the postage describe what you sent, while the delivery outcome only ever describes what came back.
saying these in an interview costs you the question
- Says LogDetail's eight values are usable on both sides
- Thinks then().log().params() prints the query string
- Expects a compile error when LogDetail.STATUS reaches a request filter
- Believes the enum is a hint the printer may ignore
- Confuses what ALL prints on the request with what it prints on the response