Foundation · Build
Content Negotiation
The Accept header picks among the formats your HttpMessageConverters support; negotiation fails loudly when no converter can produce a match.
Primary source: Spring MVC: Content Negotiation
Lesson 6 of 11
1d streakThe Architectural Question
APIs hard-coded to JSON cannot serve partners locked into XML without duplicating every endpoint or bolting on an external transformer.
What this guide proves
- Accept Header
- HttpMessageConverter
- Jackson/JAXB
Content-Type vs Accept: Two sides of the media negotiation
HTTP content negotiation allows clients and servers to agree on the data format used in request payloads and response bodies. A single endpoint can serve both JSON and XML without altering business logic.
Architectural Boundary · Do Not Confuse
Content-Type Header
Accept Header
Content-Type specifies the format of the data being sent in the current request body (e.g., application/json). Accept specifies the media types that the client is willing to receive in the response body (e.g., application/json, application/xml).
How Spring resolves HttpMessageConverters
- 01Client sends GET /api/orders with Accept: application/xml.
- 02DispatcherServlet consults ContentNegotiationManager to parse requested MediaTypes in priority order.
- 03HandlerAdapter executes the controller method and receives an OrderDto object.
- 04RequestResponseBodyMethodProcessor iterates through all registered HttpMessageConverter beans.
- 05If jackson-dataformat-xml is present, MappingJackson2XmlHttpMessageConverter matches both the MediaType and the return class.
- 06If no converter can satisfy the Accept header, Spring aborts with HttpMediaTypeNotAcceptableException (406 Not Acceptable).
Dual JSON and XML representation in practice
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>package com.example.customer.api;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/customers")
public class CustomerController {
@GetMapping(value = "/{id}", produces = {"application/json", "application/xml"})
public CustomerResponse getCustomer(@PathVariable Long id) {
return new CustomerResponse(id, "Acme Corp", "contact@acme.com");
}
}
record CustomerResponse(Long id, String name, String email) {}Break it deliberately: 406 Not Acceptable vs 415 Unsupported Media Type
Test 1: Request with unsupported Accept header curl -i -H "Accept: application/yaml" http://localhost:8080/api/customers/1 HTTP/1.1 406 Not Acceptable Test 2: POST request with unsupported Content-Type header curl -i -X POST -H "Content-Type: text/plain" -d "raw text" http://localhost:8080/api/customers HTTP/1.1 415 Unsupported Media Type
Active Recall Checkpoint
What is the diagnostic difference between an HTTP 406 error and an HTTP 415 error in Spring MVC?
Hint: Think about which header failed: incoming request body vs outgoing response body.
Show answer & explanation
415 Unsupported Media Type occurs when the server does not have a converter capable of reading the request body specified by the Content-Type header. 406 Not Acceptable occurs when the server cannot serialize the response into any of the media types requested in the client’s Accept header.
Negotiation strategies in production
Use it when
Rely on standard Accept headers for content negotiation when building public enterprise APIs serving heterogeneous clients.
Reconsider when
Avoid using URL file extensions (e.g. /customers/1.json) as they complicate route mapping and are deprecated in modern Spring Framework versions.
Runtime Architecture & Flow
Decision canvas
Evaluate the choice across three constraints
These are comparison criteria, not sequential steps. A strong answer states which constraint dominates in the current system.
Accept Header
Ask how each option changes this guarantee, its operational cost, and its failure mode.
HttpMessageConverter
Ask how each option changes this guarantee, its operational cost, and its failure mode.
Jackson/JAXB
Ask how each option changes this guarantee, its operational cost, and its failure mode.
Decision prompt: Add the Jackson XML dependency and use Postman to request the same endpoint with `Accept: application/json` and `Accept: application/xml`.
Working Implementation
Code Walkthrough
Add the Jackson XML dependency and use Postman to request the same endpoint with `Accept: application/json` and `Accept: application/xml`.
package com.example.content;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/v1/reports")
public class ContentNegotiationLab {
public record ReportSummary(String reportId, String title, int count) {}
// Produces both JSON and XML depending on the incoming 'Accept' header
@GetMapping(
value = "/{id}",
produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }
)
public ReportSummary getReport(@PathVariable String id) {
return new ReportSummary(id, "Monthly Performance", 42);
}
}Synthesis & Production Verification
Production Acceptance Criteria
- Serve JSON and XML from one endpoint driven by the Accept header
- Explain how converter selection order affects output
- Predict 406 versus 415 for mismatched Accept and Content-Type values
Key Takeaway
Content negotiation aligns client media expectations with server representation capabilities through Content-Type and Accept headers.
Architectural & Technical Review
Core Interview Questions
Q01What is the functional difference between Content-Type and Accept headers?Show answer
Content-Type declares the format of the incoming request body. Accept specifies the media types acceptable for the outgoing response body.
Q02How does Spring select an HttpMessageConverter for response serialization?Show answer
It evaluates the requested Accept media types against registered converters, matching both media type and the controller method return type.
Q03What causes an HTTP 406 Not Acceptable status code?Show answer
When no registered HttpMessageConverter can produce any of the media types requested in the client Accept header.
Production Pitfalls
Critical Anti-Patterns
- Pitfall: Using URL file extensions for content negotiation — Path extensions (e.g. /orders.json) complicate route patterns and are deprecated in modern Spring Framework versions.
- Pitfall: Assuming all clients parse JSON by default — Enterprise clients may send explicit Accept headers or request XML; configure sensible media defaults or return 406 cleanly.
Primary Documentation & Specifications
Lesson Primary References
Supplementary Module Resources