In situations where an API is being consumed by multiple systems, you might be required to provide the response in different formats depending on the client. One client might accept JSON while the other can only work with XML. That’s where the Request Content Negotiation comes into picture. In this post, we’ll explore a specific usecase of the request content negotiation where a client sends their preferences for the mediatype of their choice.
The examples in this post use
- Java 18
- Spring Boot 2.7.1
- Maven 3.8.6
- curl (to send HTTP requests)
- xmlstarlet (to format xml)
- jq (to format json)
Spring supports the following strategies for the content negotiation.
- Suffix Pattern matching (deprecated)
- Query Parameter mapping
Accept
header field
Suffix Pattern matching (deprecated)
Suffix Pattern matching was historically used when an HTTP client wasn’t able to send proper Accept
request headers. For example, a request GET /game/trial.xml
matches with @GetMapping("/game/trial")
and the response is an XML document.
Suffix pattern matching is now deprecated and turned off by default. The reasoning behind the deprecation is explained in detail in the docs here.
Query Parameter mapping
Query Parameter mapping is the preferred way to handle content negotiation when the HTTP clients can’t send proper Accept
request headers. For example, a request GET /game/trial?format=xml
matches to @GetMapping("/game/trial")
and the response is an XML document.
To enable this, open application.yml
(or application.properties
) of the Spring project and add the following configuration.
spring:
mvc:
contentnegotiation:
favor-parameter: true
By default, format
is the query parameter to pass the acceptable format. Here’s an example to get the response in XML.
?format=xml | xml fo -o
curl -s http://localhost:8080/game/trial<Game>
<title>Control</title>
<publisher>Remedy Entertainment</publisher>
</Game>
The default response format is JSON (unless specified / configured otherwise).
| jq
curl -s http://localhost:8080/game/trial
{"title": "Control",
"publisher": "Remedy Entertainment"
}
A different parameter name can also be configured through the following configuration.
spring:
mvc:
contentnegotiation:
favor-parameter: true
parameter-name: mediatype
Spring supports a lot of media types out-of-the-box. But custom media types can also be configured as follows.
spring:
mvc:
contentnegotiation:
favor-parameter: true
parameter-name: mediatype
media-types.toml: application/toml
To support custom media types, you might have to provide additional dependencies and converters to Spring.
Accept
header field
Sending the Accept
request headers is the default content negotiation strategy provided by Spring.
'Accept: application/xml' | xml fo -o
curl -s http://localhost:8080/game/trial -H <Game>
<title>Control</title>
<publisher>Remedy Entertainment</publisher>
</Game>
Similarly, a request for JSON response returns:
'Accept: application/json' | jq
curl -s http://localhost:8080/game/trial -H
{"title": "Control",
"publisher": "Remedy Entertainment"
}
Source code
Related