<chapter id="Jakarta_REST_Content_Negotiation">
   <title>&REST-API; Content Negotiation</title>

   <para>

      The HTTP protocol has built in content negotiation headers that allow the client and server to specify what
      content they are transferring and what content they would prefer to get. The server declares content preferences
      via the @Produces and @Consumes headers.
   </para>
   <para>


      @Consumes is an array of media types that a particular resource or resource method consumes. For example:
   </para>
   <para>

<programlisting>
@Consumes("text/*")
@Path("/library")
public class Library {

    @POST
    public String stringBook(String book) {...}

    @Consumes("text/xml")
    @POST
    public String jaxbBook(Book book) {...}
}
</programlisting>
   </para>
   <para>

      When a client makes a request, &REST-API; first finds all methods that match the path, then, it those matches based on
      the content-type header sent by the client.
      So, if a client sent:
   </para>
   <para>

<programlisting>
POST /library
Content-Type: text/plain

This is a nice book
</programlisting>
   </para>
   <para>

      The stringBook() method would be invoked because it matches to the default &quot;text/*&quot; media type. Now, if
      the client instead sends XML:
   </para>
   <para>

<programlisting>
POST /library
Content-Type: text/xml

&lt;book name="EJB 3.0" author="Bill Burke"/&gt;
</programlisting>
   </para>
   <para>

      The jaxbBook() method would be invoked.
   </para>
   <para>


      The @Produces is used to map a client request and match it up to the client's Accept header. The Accept HTTP
      header is sent by the client and defines the media types the client prefers to receive from the server.
   </para>
   <para>


<programlisting>
@Produces("text/*")
@Path("/library")
public class Library {

@GET
@Produces("application/json")
public String getJSON() {...}

@GET
public String get() {...}
</programlisting>
   </para>
   <para>

      So, if the client sends:
   </para>
   <para>

<programlisting>
GET /library
Accept: application/json
</programlisting>
   </para>
   <para>

      The getJSON() method would be invoked.
   </para>
   <para>


      @Consumes and @Produces can list multiple media types that they support. The client's Accept header can also send
      multiple types it might like to receive. More specific media types are chosen first. The client Accept header or
      @Produces @Consumes can also specify weighted preferences that are used to match requests with resource
      methods. This is best explained by RFC 2616 section 14.1 . RESTEasy supports this complex way of doing content
      negotiation.
   </para>
   <para>


   </para>
   <para>

      A variant in &REST-API; is a combination of media type, content-language, and content encoding as well as etags, last
      modified headers, and other preconditions. This is a more complex form of content negotiation that is done
      programmatically by the application developer using the jakarta.ws.rs.core.Variant, VarianListBuilder, and Request
      objects. Request is injected via @Context. Read the javadoc for more info on these.
   </para>
<sect1 id="media_mappings">
<title>URL-based negotiation</title>
<para>
Some clients, like browsers, cannot use the Accept and Accept-Language headers to negotiation the representation's media type
or language.  RESTEasy allows the mapping of file name suffixes like (.xml, .txt, .en, .fr) to media types and languages.
   These file name suffixes take the place and override any Accept header sent by the client.
   They are configured using the <code>resteasy.media.type.mappings</code> and <code>resteasy.language.mappings</code>
parameters. If configured within the application's web.xml, it would look like:
</para>
<programlisting><![CDATA[
<web-app>
    <display-name>Archetype Created Web Application</display-name>
    <context-param>
        <param-name>resteasy.media.type.mappings</param-name>
        <param-value>html : text/html, json : application/json, xml : application/xml</param-value>
    </context-param>

   <context-param>
        <param-name>resteasy.language.mappings</param-name>
        <param-value>en : en-US, es : es, fr : fr</param-value>
   </context-param>

   ...
</web-app>]]>
</programlisting>

<para>See <xref linkend="microprofile_config"/> for more information about application configuration. </para>

<para>
Mappings are a comma delimited list of suffix/mediatype or suffix/language mappings.  Each mapping is
   delimited by a ':'.  If GET /foo/bar.xml.en is invoked , this would be equivalent to invoking the
   following request:
</para>
<programlisting>
GET /foo/bar
Accept: application/xml
Accept-Language: en-US
</programlisting>
<para>
The mapped file suffixes are stripped from the target URL path before the request is dispatched to a corresponding &REST-API; resource.
</para>
</sect1>

<sect1 id="param_media_mappings">
<title>Query String Parameter-based negotiation</title>
<para>
RESTEasy can do content negotiation based in a parameter in the query string. To enable this, the
   parameter <code>resteasy.media.type.param.mapping</code>
should be configured in the web.xml file.  It would look like the following:
</para>
<programlisting><![CDATA[
<web-app>
    <display-name>Archetype Created Web Application</display-name>
    <context-param>
        <param-name>resteasy.media.type.param.mapping</param-name>
        <param-value>someName</param-value>
    </context-param>

    ...
</web-app>]]>
</programlisting>

<para>See <xref linkend="microprofile_config"/> for more information about application configuration. </para>

<para>The param-value is the name of the query string parameter that RESTEasy will use in the place of the Accept header.</para>
<para>Invoking http://service.foo.com/resouce?someName=application/xml, will give the application/xml media type the highest priority in the content negotiation.</para>
<para>In cases where the request contains both the parameter and the Accept header, the parameter will be more relevant.</para>
<para>It is possible to leave the param-value empty, that will cause the processor to look for a parameter named 'accept'.</para>
</sect1>

</chapter>
