WAS v8.5 > End-to-end paths > Web services - RESTful services > Use content negotiation to serve multiple content types in JAX-RS applications > Step 4. Implement content negotiation to serve multiple content types.Implement content negotiation based on HTTP headers
REST applications can return different representations of resources. We can use content negotiation based on HTTP Accept headers to determine the content format used to exchange data between servers and clients. Resources can represent data in different formats. We can implement content negotiation based on URLs, request parameters, or HTTP headers. This task describes content negotiation based on HTTP Accept headers for sending and receiving different data formats.
When a web browser makes a request, it sends information about what it is looking for to the server in headers. One of these headers is the Accept header. The Accept header tells the server what formats or MIME types the client is looking for. We can use the HTTP Accept headers to determine the content format used to exchange data.
While the Accept header is not as visible as URLs or parameters, this header is a more flexible method of handling content negotiation. We can also use the HTTP Accept, Accept-Charset, Accept-Language, and Accept-Encoding headers to determine the type of content that is returned from the server.
Using HTTP Accept headers, we can assign degrees of quality to acceptable responses. For example, a client can indicate XML is the preferred response content type. However, if XML is not available, the client can accept JSON or plain text for the format.
For example, if the Accept header contains a value such as...
application/json; q=1.0, text/xml;q=0.5, application/xml;q=0.5
...JSON is preferred but XML is acceptable as well.
In other methods of content negotiation, typically only one preferred response type exists. However, we can use the HTTP Accept headers to inform the service of all the possible types that are acceptable to the client in one request. The HTTP Accept and its related headers are part of the HTTP standard.
It is important to consider the following aspects when implementing content negotiation using HTTP headers. Some clients might send incorrect values and some services might not respect the Accept HTTP headers. Also, processing all the HTTP headers and calculating the optimal response is not as straightforward as requesting content based on a URL or a request parameter.
- Add a @javax.ws.rs.core.Context javax.ws.rs.core.Request parameter to the resource method.
- Use the javax.ws.rs.core.Variant.VariantListBuilder object to build a list of possible response variants the service supports.
- Test for an acceptable response.
Use the javax.ws.rs.core.Request.selectVariant(java.util.List<Variant>variant) method to determine if you receive an acceptable response to send to the client. A list of possible response variants is passed into the method. A variant represents a media type, language, and encoding combination. See the javax.ws.rs.core.Variant and javax.ws.rs.core.Variant.VariantListBuilder API documentation for more information about building a list of variants.
Based on the possible response variants and the incoming request HTTP headers, the selectVariant(java.util.List<Variant> variant) method returns the best possible response variant that matches the HTTP headers.
The following example demonstrates using the @javax.ws.rs.core.Context annotation to inject the javax.ws.rs.core.Request type. The javax.ws.rs.core.Request type can help determine the optimal response variant. In this example, a Request object is passed in by the runtime environment when the resource method is called.
@Path("/resources") public class Resource { @Path("{resourceID}") @GET public Response getResource(@PathParam("resourceID") String resourceID, @Context Request req) { /* This method builds a list of possible variants. */ /* You must call Variant.VariantListBuilder.add() object before calling the Variant.VariantListBuilder.build() object. */ List<Variant> responseVariants = Variant .mediaTypes( MediaType.valueOf(MediaType.APPLICATION_XML + ";charset=UTF-8"), MediaType.valueOf(MediaType.APPLICATION_XML + ";charset=shift_jis"), MediaType .valueOf(MediaType.APPLICATION_JSON)) .encodings("gzip", "identity", "deflate").languages(Locale.ENGLISH, Locale.FRENCH, Locale.US).add().build(); /* Based on the Accept* headers, an acceptable response variant is chosen. If there is no acceptable variant, selectVariant will return a null value. */ Variant bestResponseVariant = req.selectVariant(responseVariants); if(bestResponseVariant == null) { /* Based on results, the optimal response variant can not be determined from the list given. */ return Response.notAcceptable().build(); } MediaType responseMediaType = bestResponseVariant.getMediaType(); /* This instruction obtains the acceptable language and modifies the response entity. */ Locale responseLocale = bestResponseVariant.getLanguage(); if(responseMediaType.isCompatible(MediaType.APPLICATION_XML_TYPE)) { return Response.ok(/* entity in XML format */).type(MediaType.APPLICATION_XML).build(); } else if (responseMediaType.isCompatible(MediaType.APPLICATION_JSON_TYPE)) { return Response.ok(/* The entity is in JSON format */) .type(MediaType.APPLICATION_JSON).build(); } return Response.notAcceptable(Variant.mediaTypes(MediaType.APPLICATION_XML_TYPE, MediaType.APPLICATION_JSON_TYPE).add().build()).build(); } }
Results
You have implemented content negotiation using Accept headers to determine the formats for resources that represent data.
Related
Use content negotiation to serve multiple content types in JAX-RS applications
Implement content negotiation based on URL patterns
Implement content negotiation based on request parameters
Reference:
Web services specifications and APIs