+

Search Tips   |   Advanced Search

Implement content negotiation based on HTTP headers

REST applications can return different representations of resources. 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. The Accept header tells the server what formats or MIME types the client is looking for.

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 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, the following Accept header value indicates that JSON is preferred, but XML is acceptable as well.

Here is example Fiddler trace...

  1. Add parameter...

      @javax.ws.rs.core.Context javax.ws.rs.core.Request

    ...to the resource method.

  2. To build a list of possible response variants that the service supports, use the object...

      javax.ws.rs.core.Variant.VariantListBuilder

  3. Test for an acceptable response.

    To determine if you receive an acceptable response to send to the client, use the method...

      javax.ws.rs.core.Request.selectVariant(java.util.List<Variant>variant)

    A list of possible response variants is passed into the method. A variant represents a media type, language, and encoding combination.

    Based on the possible response variants, and the incoming request HTTP headers, the method...

      selectVariant(java.util.List<Variant> variant)

    ...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. */
    
            /* Call Variant.VariantListBuilder.add() before calling Variant.VariantListBuilder.build() */
    
             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 tasks

  • 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

  • Web services specifications and APIs