0
# Negotiator
1
2
Negotiator is an HTTP content negotiation library for Node.js applications that automatically selects the most appropriate response format based on client preferences expressed in HTTP Accept headers. It supports negotiation for media types, languages, character sets, and encodings, parsing quality values and priority rankings to determine optimal matches from available options.
3
4
## Package Information
5
6
- **Package Name**: negotiator
7
- **Package Type**: npm
8
- **Language**: JavaScript (Node.js)
9
- **Installation**: `npm install negotiator`
10
11
## Core Imports
12
13
```javascript
14
const Negotiator = require('negotiator');
15
```
16
17
## Basic Usage
18
19
```javascript
20
const Negotiator = require('negotiator');
21
22
// Create negotiator from request object
23
const negotiator = new Negotiator(request);
24
25
// Negotiate media types
26
const availableTypes = ['text/html', 'application/json', 'text/plain'];
27
const preferredType = negotiator.mediaType(availableTypes);
28
// Returns: 'text/html' (if client prefers HTML)
29
30
// Negotiate languages
31
const availableLanguages = ['en', 'es', 'fr'];
32
const preferredLanguage = negotiator.language(availableLanguages);
33
// Returns: 'en' (if client prefers English)
34
35
// Negotiate encodings
36
const availableEncodings = ['gzip', 'identity'];
37
const preferredEncoding = negotiator.encoding(availableEncodings);
38
// Returns: 'gzip' (if client accepts gzip)
39
```
40
41
## Architecture
42
43
Negotiator is built around a single constructor class that provides:
44
45
- **Constructor-based API**: Create instances from HTTP request objects containing Accept headers
46
- **Negotiation Methods**: Methods for each HTTP Accept header type (Accept, Accept-Language, Accept-Charset, Accept-Encoding)
47
- **Quality Value Parsing**: Automatic parsing of q-values and priority rankings according to RFC 2616
48
- **Backward Compatibility**: Legacy method aliases for older API versions
49
50
## Capabilities
51
52
### Media Type Negotiation
53
54
Negotiates the best media type from the Accept header based on client preferences and available options.
55
56
```javascript { .api }
57
/**
58
* Create a Negotiator instance from a request object
59
* @param {Object} request - HTTP request object with headers property
60
*/
61
function Negotiator(request);
62
63
/**
64
* Returns the most preferred media type from client
65
* @param {string[]} [available] - Array of available media types
66
* @returns {string|undefined} Most preferred media type, '*/*' if no Accept header, or undefined if none match
67
*/
68
Negotiator.prototype.mediaType(available);
69
70
/**
71
* Returns array of preferred media types ordered by client preference
72
* @param {string[]} [available] - Array of available media types
73
* @returns {string[]} Array of media types in preference order
74
*/
75
Negotiator.prototype.mediaTypes(available);
76
```
77
78
**Usage Examples:**
79
80
```javascript
81
const negotiator = new Negotiator(request);
82
83
// Get all client preferences in order
84
const allTypes = negotiator.mediaTypes();
85
// Returns: ['text/html', 'application/json', 'text/plain']
86
87
// Get best match from available types
88
const available = ['application/json', 'text/plain'];
89
const best = negotiator.mediaType(available);
90
// Returns: 'application/json' (if client prefers JSON over plain text)
91
```
92
93
### Language Negotiation
94
95
Negotiates the best language from the Accept-Language header based on client preferences and available options.
96
97
```javascript { .api }
98
/**
99
* Returns the most preferred language from client
100
* @param {string[]} [available] - Array of available languages
101
* @returns {string|undefined} Most preferred language, '*' if no Accept-Language header, or undefined if none match
102
*/
103
Negotiator.prototype.language(available);
104
105
/**
106
* Returns array of preferred languages ordered by client preference
107
* @param {string[]} [available] - Array of available languages
108
* @returns {string[]} Array of languages in preference order
109
*/
110
Negotiator.prototype.languages(available);
111
```
112
113
**Usage Examples:**
114
115
```javascript
116
const negotiator = new Negotiator(request);
117
118
// Get client language preferences
119
const languages = negotiator.languages();
120
// Returns: ['en-US', 'en', 'es'] (based on Accept-Language header)
121
122
// Find best match from available languages
123
const available = ['en', 'fr', 'de'];
124
const bestLanguage = negotiator.language(available);
125
// Returns: 'en' (if client prefers English)
126
```
127
128
### Charset Negotiation
129
130
Negotiates the best character set from the Accept-Charset header based on client preferences and available options.
131
132
```javascript { .api }
133
/**
134
* Returns the most preferred charset from client
135
* @param {string[]} [available] - Array of available charsets
136
* @returns {string|undefined} Most preferred charset, '*' if no Accept-Charset header, or undefined if none match
137
*/
138
Negotiator.prototype.charset(available);
139
140
/**
141
* Returns array of preferred charsets ordered by client preference
142
* @param {string[]} [available] - Array of available charsets
143
* @returns {string[]} Array of charsets in preference order
144
*/
145
Negotiator.prototype.charsets(available);
146
```
147
148
**Usage Examples:**
149
150
```javascript
151
const negotiator = new Negotiator(request);
152
153
// Get charset preferences
154
const charsets = negotiator.charsets();
155
// Returns: ['utf-8', 'iso-8859-1'] (if no Accept-Charset, defaults to '*')
156
157
// Find best charset match
158
const available = ['utf-8', 'iso-8859-1', 'ascii'];
159
const bestCharset = negotiator.charset(available);
160
// Returns: 'utf-8' (if client prefers UTF-8)
161
```
162
163
### Encoding Negotiation
164
165
Negotiates the best encoding from the Accept-Encoding header based on client preferences and available options. Supports preferred encoding arrays for tie-breaking.
166
167
```javascript { .api }
168
/**
169
* Returns the most preferred encoding from client
170
* @param {string[]} [available] - Array of available encodings
171
* @param {Object} [options] - Options object
172
* @param {string[]} [options.preferred] - Preferred encodings for tie-breaking
173
* @returns {string|undefined} Most preferred encoding, 'identity' if no Accept-Encoding header, or undefined if none match
174
*/
175
Negotiator.prototype.encoding(available, options);
176
177
/**
178
* Returns array of preferred encodings ordered by client preference
179
* @param {string[]} [available] - Array of available encodings
180
* @param {Object} [options] - Options object
181
* @param {string[]} [options.preferred] - Preferred encodings for tie-breaking
182
* @returns {string[]} Array of encodings in preference order
183
*/
184
Negotiator.prototype.encodings(available, options);
185
```
186
187
**Usage Examples:**
188
189
```javascript
190
const negotiator = new Negotiator(request);
191
192
// Get encoding preferences
193
const encodings = negotiator.encodings();
194
// Returns: ['gzip', 'deflate', 'identity'] (based on Accept-Encoding)
195
196
// Find best encoding with server preferences
197
const available = ['gzip', 'deflate', 'identity'];
198
const options = { preferred: ['gzip', 'deflate'] };
199
const bestEncoding = negotiator.encoding(available, options);
200
// Returns: 'gzip' (if client accepts and server prefers gzip)
201
202
// Identity encoding is automatically added with lowest quality if not specified
203
const identityIncluded = negotiator.encodings(['gzip']);
204
// Returns: ['gzip', 'identity'] (identity added automatically)
205
```
206
207
## Backward Compatibility Methods
208
209
Legacy method names are supported for backward compatibility:
210
211
```javascript { .api }
212
// These are aliases to the main methods
213
Negotiator.prototype.preferredCharset = Negotiator.prototype.charset;
214
Negotiator.prototype.preferredCharsets = Negotiator.prototype.charsets;
215
Negotiator.prototype.preferredEncoding = Negotiator.prototype.encoding;
216
Negotiator.prototype.preferredEncodings = Negotiator.prototype.encodings;
217
Negotiator.prototype.preferredLanguage = Negotiator.prototype.language;
218
Negotiator.prototype.preferredLanguages = Negotiator.prototype.languages;
219
Negotiator.prototype.preferredMediaType = Negotiator.prototype.mediaType;
220
Negotiator.prototype.preferredMediaTypes = Negotiator.prototype.mediaTypes;
221
```
222
223
## Error Handling
224
225
**Single methods** (`.mediaType()`, `.language()`, `.charset()`, `.encoding()`):
226
- Return default values when no Accept header is present (`*/*`, `*`, `*`, `identity` respectively)
227
- Return `undefined` when no acceptable match is found from available options
228
229
**Array methods** (`.mediaTypes()`, `.languages()`, `.charsets()`, `.encodings()`):
230
- Return arrays with default values when no Accept header is present
231
- Return arrays with acceptable matches in preference order
232
- Return empty arrays when no acceptable matches are found
233
234
```javascript
235
const negotiator = new Negotiator(request);
236
237
// No matching media type from available options
238
const result = negotiator.mediaType(['application/xml']);
239
// Returns: undefined (if client doesn't accept XML)
240
241
// No Accept header present - returns default
242
const defaultType = negotiator.mediaType();
243
// Returns: '*/*' (RFC 2616 default)
244
245
// Array method with no header - returns default array
246
const allTypes = negotiator.mediaTypes();
247
// Returns: ['*/*'] (default array when no Accept header)
248
```
249
250
## Quality Values and RFC 2616 Compliance
251
252
Negotiator follows RFC 2616 specifications for HTTP content negotiation:
253
254
- Quality values (q-values) are parsed and respected (e.g., `text/html;q=0.8`)
255
- Missing headers are treated according to RFC defaults (e.g., `*` for charset, `*/*` for media types)
256
- Specificity rules are applied (more specific matches take precedence)
257
- Wildcard matching is supported (`*/*`, `text/*`, `*`)
258
259
## Types
260
261
```javascript { .api }
262
/**
263
* HTTP request object expected by Negotiator constructor
264
*/
265
interface Request {
266
headers: {
267
accept?: string;
268
'accept-language'?: string;
269
'accept-charset'?: string;
270
'accept-encoding'?: string;
271
};
272
}
273
274
/**
275
* Options object for encoding negotiation
276
*/
277
interface EncodingOptions {
278
preferred?: string[];
279
}
280
```