How does content negotiation work in Spring MVC?
Quick Answer
Content negotiation determines which representation format (JSON, XML, etc.) a response should be serialized into, based on what the client indicates it can accept — primarily the HTTP Accept request header, though Spring can also be configured to consider a URL path extension or a query parameter. Spring MVC selects an appropriate HttpMessageConverter that can produce a media type matching the client's preference (JSON via Jackson is the near-universal default in modern APIs), returning a 406 Not Acceptable if no converter can satisfy the request.
Detailed Answer
Content negotiation is how Spring MVC decides which representation format to serialize a response body into, when a resource could potentially be returned as JSON, XML, or something else.
Primary mechanism — the Accept request header: the client states what media types it can handle, in preference order:
GET /api/orders/42
Accept: application/json
Spring MVC consults its registered HttpMessageConverters (Jackson's JSON converter is registered by default when spring-boot-starter-web is on the classpath) to find one that both understands the response's Java type and can produce a media type matching the client's Accept header — Jackson producing application/json satisfies that request.
@GetMapping(value = "/orders/{id}", produces = { "application/json", "application/xml" })
Order getOrder(@PathVariable Long id) { ... }
// same handler can serve either representation, depending on the client's Accept header
If no registered converter can produce any media type the client says it will accept, Spring MVC responds with 406 Not Acceptable.
Alternative negotiation strategies (less common, and generally discouraged in modern API design in favor of the Accept header alone):
- Path extension (
/orders/42.json//orders/42.xml) — historically supported but disabled by default in modern Spring Boot, partly due to security concerns (URL-extension-based negotiation has been a source of exploits in some frameworks) and ambiguity with actual resource paths containing dots. - Query parameter (
/orders/42?format=json) — can be enabled viaContentNegotiationConfigurer, but similarly less idiomatic than relying on the standardAcceptheader.
In practice for most modern REST APIs: since virtually all clients and APIs standardize on JSON, explicit content negotiation configuration is rarely a major concern day-to-day — Jackson's JSON converter, registered automatically by Spring Boot's auto-configuration, handles the overwhelming majority of real-world traffic without any extra setup, and content negotiation mainly becomes an explicit topic when an API genuinely needs to support multiple formats (e.g., JSON and XML) for different classes of clients.