UNPKG

5.62 kBMarkdownView Raw
1# Content Negotiation
2
3MIME types are an important foundation for RESTful services, and often misunderstood. Most web developers understand that the server returns a 'Content-Type' along with a response entity. Many forget that the client is responsible for expressing what MIME types the client is able to handle, and what its preferred MIME types are. This dance between the client and server to settle on the type of the response is known as content negotiation. Content negotiation is a fundamental aspect of REST and differentiates rest.js from many other HTTP clients that do not embrace content negotiation.
4
5rest.js provides support for encoding and decoding request and response entities based on the 'Content-Type'. The response is not presumed to be XML or JSON or any other type. When making a request, the 'Accept' header is used to indicate the types the client understand and the relative preference of different types. A typical accept header from a browser may look like:
6
7`text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8`.
8
9This string indicates that HTML and XHTML are the most preferred, weighted at 1.0 on a scale between 0 and 1. XML is next at 0.9 and everything else is last at 0.8. Using this info the server will figure out for the resource requested, what MIME types it's able to render the resource as and finds the best match to send to the client.
10
11
12<a name="module-rest/mime/registry"></a>
13## MIME Registry
14
15`rest/mime/registry` ([src](../mime/registry.js))
16
17A registry of converters for MIME types is provided. Each time a request or response entity needs to be encoded or decoded, the 'Content-Type' is used to lookup a converted from the registry. The converter is then used to serialize/deserialize the entity across the wire.
18
19Registry lookups may be asynchronous as converters are lazily loaded. As such a promise for the converter is returned for all lookups.
20
21```javascript
22registry.lookup('application/json').then(function (jsonConverter) {
23 ...
24});
25```
26
27
28<a name="mime-converters"></a>
29## MIME Converters
30
31Serveral common MIME types are supported out of the box including:
32
33- text/plain
34- application/hal+json
35- application/json
36- application/x-www-form-urlencoded
37- multipart/form-data *
38
39These converters are loaded lazily and are located under `rest/mime/type/*`. So 'text/plain' is resolved to `rest/mime/type/text/plain`. The main MIME registry knows how to fetch these converters. Child registries extend from the main registry hierarchically and thus also get access to these provided converters.
40
41* Multipart support is only available for requests from browsers that has implemented XMLHttpRequest 2. This includes most modern browsers with the exception of IE <=9.
42
43<a name="mime-converters-custom"></a>
44### Custom Converters
45
46A converter is fundamentally a object with two methods: `read` and `write`. The read method accepts the entity as a string and returns an object. The write method accepts the entity as an object and returns a string. While not strictly required, the read and write methods are typically reflexive. A convert may implement either the read or write methods, but that limits the converters ability to handle response or request entities, respectively.
47
48The `read` and `write` methods may additionaly accept an `opts` argument. Common opts include the `request` or `response`, and a `client` to make further requests if needed. Either a raw value or a promise may be returned.
49
50```javascript
51numberConverter = {
52 read: function (str, opts) {
53 return parseFloat(str);
54 },
55 write: function (obj, opts) {
56 return obj.toString();
57 }
58};
59
60registry.register('application/vnd.numbers', numberConverter);
61```
62
63Converters registered within the registry will be available to all consumers of the registry. If a custom converter needs to be installed to override a well known MIME type, or different parts of the application need different converters for the same MIME type, a child registry should be used instead. The custom registry can be provided to the mime interceptor to override using the main registry.
64
65```javascript
66childRegistry = registry.child();
67childRegistry.register('application/json', fauxJsonConverter);
68
69registry.lookup('application/json').then(function (jsonConverter) {
70 // the real converter
71 refute.same(jsonConverter, fauxJsonConverter);
72});
73
74childRegistry.lookup('application/json').then(function (jsonConverter) {
75 // the faux converter
76 assert.same(jsonConverter, fauxJsonConverter);
77});
78```
79
80Converters need to be registered for a MIME type. MIME types are well known and [registered with IANA](http://www.iana.org/assignments/media-types). It's frowned upon to use a MIME type that is not registered, or use a registered MIME for an incompatible format.
81
82Vendor MIMEs '\*/vnd.*' are unreserved and available for internal use and experimentation. Application may use vendor MIMEs to provide additional knowledge about the type of object an entity represents, or to vary the rendering of the same object. As an example, 'application/json' provides a strong structure for the entity, but does nothing to indicate what the entity represents. Vendor MIMEs can provide that extra semantic meaning, but requires both the client and server understand and establish that meaning out-of-band.
83
84
85<a name="mime-interceptor"></a>
86## MIME Interceptor
87
88`rest/interceptor/mime` ([src](../interceptor/mime.js))
89
90The [MIME interceptor](interceptors.md#module-rest/interceptor/mime) utilizes the mime registry to convert request and response entities between objects and text strings.