Content Negotiation in a REST API

Content negotiation is a key facet of REST APIs that empowers clients and servers to agree on the format and language of data exchanged.

Content negotiation is a key facet of REST that empowers clients and servers to agree on the format and language of data exchanged. It enables diverse systems to work seamlessly together.

Let us unravel the intricacies of content negotiation within RESTful APIs.

1. The Need of Content Negotiation

Generally, the REST resources can have multiple presentations, mostly because there may be different clients expecting different representations. However, to ensure efficient communication, both clients and servers must agree on how these resources should be represented and delivered.

Asking for a suitable presentation, when there are multiple possible representations, by a client is referred to as content negotiation.

HTTP has provisions for several mechanisms for “content negotiation” — the process of selecting the best representation for a given response when there are multiple representations available.

RFC 2616

2. Server-driven vs. Agent-driven Content Negotiation

If the selection of the best representation for a response is made by an algorithm located on the server, it is called server-driven negotiation. If that selection is made on the agent or client side, it is called agent-driven negotiation.

Practically, we will NOT find much usage of server-side negotiations because, in that way, we have to make a lot of assumptions about the client’s expectations. For example, a few things like the client context or how the client will use the resource representation are almost impossible to determine. Also, the server-driven negotiation makes the server-side code more complex, unnecessarily.

So, most REST API implementations rely on agent-driven content negotiations. Agent-driven content negotiation depends on the usage of HTTP request headers or resource URI patterns.

2.1. Content Negotiation using HTTP Headers

On the server side, an incoming request may have an entity attached to it. To determine its type, the server uses the HTTP request header ‘Content-Type‘. Some common examples of content types are “text/plain“, “application/xml“, “text/html“, “application/json“, “image/gif“, and “image/jpeg“.

Content-Type: application/json

Similarly, to determine what type of representation is desired on the client side, an HTTP header ‘ACCEPT‘ is used. It will have one of the values mentioned for Content-Type above.

Accept: application/json

Generally, if no Accept header is present in the request, the server can send a pre-configured default representation type.

Implementing Accept header based content negotiation is the most used and recommened way.

2.2. Content Negotiation using URL Patterns

Another way to pass content type information to the server is that the client may use the specific extension in resource URIs. For example, a client can ask for details using:

http://rest.api.com/v1/employees/20423.xml
http://rest.api.com/v1/employees/20423.json

In the above case, the first request URI will return an XML response while the second request URI will return a JSON response.

3. Defining Preferences

It is possible to have multiple values in Accept header using the ‘q’ parameter i.e. relative quality factor.

The client may want to provide multiple values in the accept header when the client is not sure if its desired representation is present or supported by the server at that time. [RFC 2296]

For example,

Accept: application/json,application/xml;q=0.9,*/*;q=0.8

Above Accept header allows you to ask the server for a JSON format (first choice). If it can’t, perhaps it could return XML format (the second choice). If it’s still not possible, let it return what it can.

The preference order is defined through the q parameter with values from 0 to 1. When nothing is specified, the implicit default value is 1.

4. Summary

In the intricate world of RESTful APIs, content negotiation stands as a pillar of harmonious data exchange. From single media type requests to default representation and ‘q‘ parameter, understanding these negotiation techniques is key to achieving truly flexible and adaptable RESTful APIs.

Happy Learning !!

Comments

Subscribe
Notify of
guest
16 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
Mike

Just curious, and I may need to post this under a different topic, but I was looking to determine the correlation between Accept and Content-Type headers versus swagger consumes and produces keywords. I would expect a 1-1 relation, but simply adding a produces in a swagger does not require a user to send in an accept header. Can someone explain the correlation or point me to a site that has this info? Swagger.io discusses the headers and keywords, but not their correlation, which I am looking for.

Thank you in advance for any help, and sorry if this should be under a different topic.

Oswald

I think there is some confusion in the “Content negotiation using URL patterns” because it shows an example using an extension to locate a URI. While in the “REST Resource Naming Guide” section “Do not use file extenstions” you recommend not to use file extensions.

KSN

I have different GET request with the different content-type returned.

@GET
@Produces(“application/text+xml;qs=0.75;charset=’utf-8′”)
public Source getText( ) {
}

@GET
@Produces(“application/xml;qs=0.5;charset=’utf-8′”)
public Source getXml( ){
}

When I request from FireFox which goes into the first method due to FireFox set the Accept-header: “text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8”.

Why it is going into first even the request header has “application/xml”?

Any help will be appreciated!!

Thanks in advance.

James Passmore

They are too generic, Roy Fielding in comment 31 of his blog tells us:

In terms of testing a specification, the hardest part is identifying when a RESTful protocol is actually dependent on out-of-band information or if the authors are just overspecifying things for the purpose of documentation.

What I look for are requirements on processing behavior that are defined outside of the media type specification. One of the easiest ways to see that is when a protocol calls for the use of a generic media type (like application/xml or application/json) and then requires that it be processed in a way that is special to the protocol/API.

Xavier

Isn’t “application/xml” or “application/json” a bit too generic?

Wouldn’t it be better to use vendor specific media types like “application/vnd.mycompany.customers.v1+json” or “application/vnd.mycompany.customers+json;version=1”?

You can put a lot of stuff in the ACCEPT header like the version or the charset which helps keeping your URIs clean (no version or file extension… after all, the U in URI stands for Unique, it shouldn’t change when you request another representation for the same resource).

pramod sahni

how to produce different response for different client in rest api?

steven c

are you sure about this?

Oscar

Negotiation via URI patterns is against REST resource naming best practices, isn’t it? I refer to “Consistency is the key” , where it’s advisable “Do not use file extentions”

Oscar

Thanks for your reply!!

Great tutorial 😉

steven c

true that

Eugen

If format is present via URI and Accept header what precedence should be in this case?
My personal opinion is: use URI than fall back to Accept header.
But I am not sure this is right. Is there some RFC or spec which define this priority?