This is a high-level overview of the terms and concepts underlying content negotiation.
Variants are the different ways that the underlying information behind a resource (URI) can be encoded.
Variants of the same resource may vary by language, charset, mime type or encoding; the important concept is that these variations do not affect the content of the resource but merely it’s representation.
For example, if the same image saved as PNG and JPEG would be variants for this purpose.
Quality factors are used to describe variant preferences, having a range from 1 (for the ideal representation) to 0 (for a completely degraded representation of the resource). Thee steps between are used to indicate varying levels of preference.
RFC2295 Sec 5.3 provides a guide to assigning quality factors:
1.000 perfect representation
0.900 threshold of noticeable loss of quality
0.800 noticeable, but acceptable quality reduction
0.500 barely acceptable quality
0.300 severely degraded quality
0.000 completely degraded quality
Preferences should be encoded as described in RFC2126.
In brief this is a comma-separated list, each element consisting of a type (e.g. text/html
) and optional quality factor (e.g text/html;q=0.5
).
For example, given the following preferences:
Mime Type | Relative Preference |
---|---|
application/json | Best representation available |
application/xml | Less than ideal; our data doesn't encode well in XML |
text/html | Allow fallback for humans, but not useful for other applications |
We can assign appropriate quality factors to each variant:
Mime Type | Quality Factor | Encoded |
---|---|---|
application/json | 1 | application/json;q=1 |
application/xml | 0.7 | application/xml;q=0.7 |
text/html | 0.3 | text/html;q=0.3 |
The resultant server preference string would look like application/json;q=1,application/xml;q=0.7,text/html;q=0.3
.
Content negotiation is performed in three stages:
Preference
instances.MatchedPreference
instances.Each variant specified by the server is compared to the variants provided by the client using each of the matching rules described below. The successful match with the highest precedence is applied and a MatchedPreference
is created from the client & server preferences.
Once matching is complete the generated list of MatchedPreference
is sorted by the product of the client & servers quality factors and the match with the highest value is the preferred type.
The precedence of the rules are as follows (highest to lowest):
Occurs when an exact match is found in client & server preferences.
Note: When doing mime negotiation accept-extens fragments are discarded - this means a client preference of text/html;level=4
will be an exact match for the server preference text/html
.
Specified by clients in Accept fields, these match any subtype of the parent type.
For example text/*
matches both text/html
and text/plain
but not application/json
.
Specified by the server when negotiating on the Accept-Language field, they allow the application developer to group language families as a ‘last resort’ for matching purposes.
Say your language supports Spanish (es
) - it would be burdensome to have to specify every permutation of extlangs in your server preferences (e.g. es
, es-419
, es-CO
, es-ES
).
Instead you can specify a family by using es-*
which will match any language string beginning in es
. When using the languageBest()
method the returned variant name will always be es
rather than es-*
or the client’s full language tag as this aids for direct lookup.
For all types of negotiation clients can specify catch-all variants with a wildcard (e.g. *
or */*
).
These match any server variant.
Used in one side of a MatchedPreference instance when the variant was present only in the server or client preferences.