HTTP Content Negotiation
Negotiator is a lightweight, standalone utility for parsing and evaluating HTTP `Accept`, `Accept-Language`, `Accept-Encoding`, and `Accept-Charset` headers. It allows servers to determine the client's preferred content based on quality values (`q-factors`) specified in these headers. Primarily maintained by the `jshttp` organization, it serves as a core component for web frameworks like Express.js by abstracting complex RFC specifications for content negotiation. The current stable version is `1.0.0`. The package operates in a maintenance mode, with infrequent but significant major releases that often include breaking changes to align with evolving Node.js environments and best practices. It distinguishes itself by providing a robust and dependency-free solution for this specific HTTP concern.
Common errors
-
TypeError: Negotiator is not a constructor
cause Attempting to instantiate `Negotiator` when it was imported incorrectly, often due to a named import or incorrect CommonJS `require` usage.fixFor ESM, use `import Negotiator from 'negotiator';`. For CommonJS, use `const Negotiator = require('negotiator');` and then `new Negotiator(request);`. -
Unexpected content type/language/encoding returned by negotiator.mediaType() (or similar method)
cause The `Accept` header or corresponding `Accept-` header from the client either has unexpected `q` values, a different order of preference, or the `available` list provided to the negotiator method does not match the expected options.fixInspect the raw `Accept` headers received by the server. Verify the `q` values and syntax. Ensure the `available` array passed to `negotiator.mediaType(available)` accurately reflects what your application can provide and is not empty.
Warnings
- breaking Version `1.0.0` dropped support for Node.js versions older than 18. Applications running on Node.js <18 must remain on `negotiator@0.6.x` or upgrade their Node.js environment.
- gotcha Incorrect understanding or parsing of `q` values (quality factors) in `Accept` headers can lead to unexpected negotiation results. The `negotiator` library correctly sorts preferences, but developers must ensure their available lists align with expected client preferences.
- gotcha Media type parameters and header values are typically case-insensitive according to HTTP specifications. Older versions (pre-0.5.3) had fixes related to case-insensitivity in matching. Ensure your application's `available` lists use consistent casing or handle potential variations if manually constructing them.
- gotcha When dealing with `Accept-Encoding`, the `identity` encoding is implicitly supported unless explicitly excluded by a `q=0` factor. The library handles this, but applications might overlook `identity` when checking for available encodings, leading to unexpected default behavior.
Install
-
npm install negotiator -
yarn add negotiator -
pnpm add negotiator
Imports
- Negotiator
import { Negotiator } from 'negotiator'import Negotiator from 'negotiator'
- Negotiator
const { Negotiator } = require('negotiator')const Negotiator = require('negotiator')
Quickstart
import Negotiator from 'negotiator';
const mockRequest = {
headers: {
'accept': 'text/html, application/xhtml+xml, application/json;q=0.9, image/webp, */*;q=0.8',
'accept-language': 'en-US,en;q=0.9,es;q=0.7',
'accept-encoding': 'gzip, deflate, br;q=0.9, identity;q=0.5'
}
};
const negotiator = new Negotiator(mockRequest);
console.log('Preferred Media Types (all):', negotiator.mediaTypes());
console.log('Preferred Media Type (available):', negotiator.mediaType(['application/json', 'text/plain']));
console.log('Preferred Languages (all):', negotiator.languages());
console.log('Preferred Language (available):', negotiator.language(['es', 'fr']));
console.log('Preferred Encodings (all):', negotiator.encodings());
console.log('Preferred Encoding (available):', negotiator.encoding(['gzip', 'br', 'identity']));
/* Example Output:
Preferred Media Types (all): [ 'text/html', 'application/xhtml+xml', 'application/json', 'image/webp', '*/*' ]
Preferred Media Type (available): application/json
Preferred Languages (all): [ 'en-US', 'en', 'es' ]
Preferred Language (available): es
Preferred Encodings (all): [ 'gzip', 'br', 'identity', 'deflate' ]
Preferred Encoding (available): gzip
*/