您的位置:首页 > 编程语言 > Go语言

RESTful之Content negotiation

2016-03-13 11:20 316 查看

Content negotiation

Content negotiation

Content negotiation means allowing different representations of a resource in the

same URI so that clients can make a choice on what suits them best.

"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, Fielding et al.

There are different patterns for content negotiation.

These are as follows:

• Using HTTP headers

• Using URL patterns

Content negotiation using HTTP headers

When the client sends requests to create or update a resource, there is some form

of payload that should be transferred from the client to the endpoint. Also, when

a response is generated, a payload can be sent back to the client. These payloads

are handled by HTTP request and response entities, which are sent as part of the

HTTP messages body.

Entities are sent via a request, usually for HTTP
POST and
PUT methods, or they

are returned in a response for the HTTP methods. The Content-Type HTTP header

is used to indicate the MIME type of the entity being sent by the server. Common

examples of content types are "text/plain",
"application/xml",
"text/html",

"application/json",
"image/gif", and
"image/jpeg".

A client can make a request to the server and specify what media types it can

handle and what is its order of preference as part of the
"Accept" HTTP header.

The client can also specify in what language it wants the response as part of the

"Accept-Language"
header to be. If no Accept
header is present in the request,

the server can send the representation it chooses.

The JAX-RS specification provides standard annotations to support content

negotiation. These are javax.ws.rs.Produces
and javax.ws.rs.Consumes

annotations. The following snippet shows an example of the
@Produces

annotation in a resource method:
@GET
@Path("orders")
@Produces(MediaType.APPLICATION_JSON)
public List<Coffee> getCoffeeList(){
return CoffeeService.getCoffeeList();
}


The getCoffeeList()
method returns a list of coffees and is annotated with

@Produces(MediaType.APPLICATION_JSON). The
@Produces
annotation is used

to specify which MIME types the resource can send back to the client and match

it up to the client's Accept
header.

This
method will produce a response as shown:

X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source
Edition 4.0 Java/Oracle Corporation/1.7)
Server: GlassFish Server Open Source Edition 4.0
Content-Type: application/json
Date: Thu, 31 Jul 2014 15:25:17 GMT
Content-Length: 268
{
"coffees": [
{
"Id": 10,
"Name": "Cappuchino",
"Price": 3.82,
"Type": "Iced",
"Size": "Medium"
},
{
"Id": 11,
"Name": "Americano",
"Price": 3.42,
"Type": "Brewed",
"Size": "Large"
}
]
}


In a resource, if no methods are able to produce the MIME type requested
by a client

request, the JAX-RS runtime sends back an HTTP 406 Not Acceptable
error.

The following snippet shows a resource method annotated with the

@Consumes
annotation:

@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response addCoffee(Coffee coffee) {
// Implementation here
}


The @Consumes
annotation specifies which media types the resource can consume.

When a client makes a request, JAX-RS finds all the methods that will match the path,

and it will then invoke the method based on the content type sent by the client.

If a resource is unable to consume the MIME type of a client request, the JAX-RS

runtime sends back an HTTP 415 ("Unsupported Media Type")
error.

Multiple MIME types can be specified in the
@Produces
or @Consumes
annotation

as @Produces(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML).

Along with the support for static content negotiation, JAX-RS also contains runtime

content negotiation support using the javax.ws.rs.core.Variant
class and the

javax.ws.rs.core.Request
objects. A Variant
object in a JAX-RS specification

is a combination of media types, content-language, and content encoding as well

as ETags, last-modified headers, and other preconditions. The
Variant object

defines the resource representation that is supported by the server. The
Variant.

VariantListBuilder class is used to build a list of representation variants.

The following code snippet shows how to create a list of resource representation

variants:

List<Variant> variants = Variant.mediatypes("application/xml",
"application/json").build();


The code snippet calls the build method of the
VariantListBuilder
class.

The Request.selectVariant
method takes a list of Variant
objects and chooses

the one based on the client's Accept
header, as shown in the following snippet:

@GET
public Response getCoffee(@Context Request r) {
List<Variant> vs = ...;
Variant v = r.selectVariant(vs);
if (v == null) {
return Response.notAcceptable(vs).build();
} else {
Coffee coffee = ..//select the representation based on v
return Response.ok(coffee, v);
}
}


Content negotiation based on URL patterns

Another approach for content negotiation adopted by some APIs is to send the

resource representation based on the extension of a resource in the URL. For

example, a client can ask for details using http://foo.api.com/v2/library/
books.xml or http://foo.api.com/v2/library/books.json. The server has

different methods, which can handle the two URIs. However, both of these are

representations of the same resource.

@Path("/v1/books/")
	public class BookResource {

	@Path("{resourceID}.xml")
	@GET
	public Response getBookInXML(@PathParam("resourceID") String
	resourceID) {
	//Return Response with entity in XML
	}
	@Path("{resourceID}.json")
	@GET
	public Response getBookInJSON(@PathParam("resourceID") String
	resourceID) {
	//Return Response with entity in JSON
	}
	}


As you can see in the preceding snippet, there are two methods defined:

getBookInXML()
and getBookInJSON(), and the response is returned based

on the path of the URL.

It is a good practice to use the HTTP content negotiation
Accept

header. Using headers for content negotiation provides a clear

separation of IT concerns from business. The other advantage with

using the Accept
header for content negotiation is that there is

only one resource method for all the different representations.

读书笔记:RESTful Java Patterns and Best Practices

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: