Explain produces vs consumes on a request mapping, and which HTTP status each drives when it fails to match.
answer
- consumes = Content-Type = 415
- produces = Accept = 406
- input side vs output side
- both are also mapping conditions
- HttpMediaTypeNotSupported / NotAcceptable
basics
~10 sconsumes matches the request body's Content-Type; a mismatch yields 415 Unsupported Media Type. produces matches the client's Accept header (what the response can be); a mismatch yields 406 Not Acceptable.
solid answer
~40 s`consumes` and `produces` are mapping conditions on `@RequestMapping`/`@PostMapping` etc. `consumes = "application/json"` means the handler only matches requests whose `Content-Type` is JSON — used for endpoints that read a `@RequestBody`. If the incoming Content-Type isn't accepted, Spring throws `HttpMediaTypeNotSupportedException` → **415 Unsupported Media Type**. `produces = "application/json"` declares which media types the method can emit; it participates in content negotiation against the `Accept` header and also acts as a mapping condition. If the client's Accept header can't be satisfied by any producible type, Spring throws `HttpMediaTypeNotAcceptableException` → **406 Not Acceptable**. Mnemonic: consumes ↔ Content-Type ↔ 415 (input), produces ↔ Accept ↔ 406 (output). Both accept multiple values and support negation (`!text/plain`).
code
java · 20 lines@RestController
@RequestMapping("/orders")
public class OrderController {
// consumes: request body must be JSON, else 415.
// produces: response is JSON; Accept must allow it, else 406.
@PostMapping(
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public OrderView create(@RequestBody OrderRequest body) {
return service.create(body);
}
// Two methods, same path, split by produces (media-type mapping):
@GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public OrderView asJson(@PathVariable long id) { return service.get(id); }
@GetMapping(value = "/{id}", produces = MediaType.APPLICATION_XML_VALUE)
public OrderView asXml(@PathVariable long id) { return service.get(id); }
}go deeper
Remember the pairing: consumes→Content-Type→415, produces→Accept→406.
Explain both as mapping conditions plus their exception/status mapping and give the media-type-mapping example.
Discuss converter canRead/canWrite involvement and customizing 406/415 error bodies.
Weigh explicit produces/consumes for contract enforcement vs. the friction of over-narrow declarations across many endpoints.
`produces` and `consumes` are attributes on the request-mapping annotations (`@RequestMapping`, `@GetMapping`, `@PostMapping`, …). They serve a dual role: they are **request-matching conditions** (part of how Spring selects the handler method) *and* they feed content negotiation. **`consumes` — the input side (request body):** - Declares which request `Content-Type`s the method can read, e.g. `@PostMapping(path = "/orders", consumes = MediaType.APPLICATION_JSON_VALUE)`. - Spring matches it against the request's **`Content-Type`** header. `consumes` narrows which requests reach this method. - If a request URL/method matches but the Content-Type does not satisfy any `consumes` condition, Spring raises **`HttpMediaTypeNotSupportedException`**, translated to **HTTP 415 Unsupported Media Type**. - It also governs which `HttpMessageConverter` reads the body for `@RequestBody`: the converter must `canRead` that Content-Type. Even without `consumes`, if no converter can read the incoming Content-Type you get 415. - Supports lists (`consumes = {"application/json", "application/xml"}`) and negation (`consumes = "!application/xml"`). **`produces` — the output side (response body):** - Declares which media types the method can emit, e.g. `@GetMapping(path = "/orders/{id}", produces = MediaType.APPLICATION_JSON_VALUE)`. - Matched against the request's **`Accept`** header. It both restricts handler selection and constrains negotiation: the chosen response type must be in the intersection of {Accept types} and {produces types} and be writable by some converter. - If nothing satisfies both, Spring raises **`HttpMediaTypeNotAcceptableException`** → **HTTP 406 Not Acceptable**. - Also supports lists and parameterized media types, e.g. `produces = "application/json;charset=UTF-8"`, and expression media types like `MediaType.APPLICATION_JSON_VALUE`. **Interaction subtleties:** - `produces` as a *condition*: two methods on the same path can be distinguished purely by `produces` (JSON vs XML) — Spring routes by the Accept header. This is 'media-type mapping'. - A common trap: adding `produces` too narrowly (e.g. only XML) causes 406 for JSON clients that would otherwise have worked via the default converter. - `consumes`/`produces` interplay with the `ContentNegotiationManager`: `produces` restricts the *producible* set that the manager's resolved Accept types are matched against. - Error rendering: In a `@RestControllerAdvice`/`ResponseEntityExceptionHandler` you can handle `HttpMediaTypeNotSupportedException` and `HttpMediaTypeNotAcceptableException` to customize the 415/406 bodies. **When to use each:** - Use `consumes` on write endpoints (POST/PUT/PATCH) to reject wrong payload formats early with a clean 415. - Use `produces` when a single path serves multiple representations, or to document/enforce that an endpoint is JSON-only.
- Two methods share a path and differ only by `produces` (JSON vs XML). A request arrives with `Accept: */*`. Which runs?Spring picks the first matching producible type in its configured order — commonly JSON if the JSON converter/mapping is ordered first. `*/*` matches both, so ordering (and defaultContentType, if set) breaks the tie rather than a 406.
- How would you return a custom JSON error body for a 415 instead of the default?Handle `HttpMediaTypeNotSupportedException` in a `@RestControllerAdvice` (or override `handleHttpMediaTypeNotSupported` in `ResponseEntityExceptionHandler`) and return a `ResponseEntity` with status 415 and your problem-detail body.
saying these in an interview costs you the question
- Saying a wrong Accept header causes 415 (it causes 406; 415 is for the request Content-Type).
- Claiming produces only documents the endpoint and has no effect on routing — it is a genuine mapping condition.
- Thinking consumes affects the response format (it only governs reading the request body).