HTTP Vary Header Parser and Utility
http-vary is a lightweight, RFC 9110 compliant utility designed for parsing and comparing HTTP Vary headers, which are crucial for ensuring correct HTTP caching behavior. It provides two primary functions: `parse()`, which normalizes a Vary header string into an array of lowercase header names (or a wildcard `'*'`), and `compare()`, used to determine if two sets of request headers are cache-equivalent based on a specified Vary header. The package is currently at version 1.0.3 and is part of the 'tinylibs' monorepo, suggesting a consistent, albeit independent, patch release cadence. Its core strength lies in its minimal footprint and strict adherence to RFC 9110, focusing exclusively on the Vary header without extraneous caching logic. This makes it ideal for environments demanding precise control over HTTP caching mechanisms. It also ships with comprehensive TypeScript types, enhancing developer experience and type safety.
Common errors
-
TypeError: (0 , http_vary__WEBPACK_IMPORTED_MODULE_0__.parse) is not a function
cause Attempting to import `parse` or `compare` using a default import syntax, or incorrectly using CommonJS `require()` without destructuring.fixUse named imports for ESM (`import { parse, compare } from 'http-vary';`) or direct destructuring for CommonJS (`const { parse, compare } = require('http-vary');`). -
TS2305: Module '"http-vary"' has no exported member 'SomeNonExistentExport'.
cause Trying to import a symbol that is not exported by the `http-vary` package, or a type/interface without `type` keyword.fixVerify the exact names of the exported functions (`parse`, `compare`) and types (`VaryHeader`). For types, use `import type { VaryHeader } from 'http-vary';`. -
Caching issues when using Vary: *
cause Misunderstanding the implications of a `Vary: *` header, which indicates that the response depends on virtually all request headers, rendering it practically uncacheable.fixReview the RFC 9110 specification for `Vary: *`. If `Vary: *` is present, `http-vary`'s `compare` function will return `false` if *any* header differs, which is correct behavior. Avoid `Vary: *` unless explicit uncacheability is desired for shared caches.
Warnings
- gotcha The `compare` function implicitly normalizes header names to lowercase for comparison. While HTTP header names are case-insensitive, inconsistent casing in input headers provided to `compare` might lead to unexpected results if not handled by the library, though `http-vary` aims to mitigate this.
- gotcha When the Vary header is `*` (wildcard), it signifies that the response varies by *any* request header not explicitly defined in RFC 9110 (such as `Authorization` or `Cookie`). This effectively makes the response uncacheable for shared caches and highly problematic for private caches, as even minor, irrelevant header changes will invalidate the cache.
- breaking The initial major release `http-vary@1.0.0` established the API. While there have been no subsequent breaking changes in `http-vary` itself, it's important to note that this marks the stable API baseline.
Install
-
npm install http-vary -
yarn add http-vary -
pnpm add http-vary
Imports
- parse
const parse = require('http-vary').parseimport { parse } from 'http-vary' - compare
import httpVary from 'http-vary'; const compare = httpVary.compare;
import { compare } from 'http-vary' - VaryHeader (type)
import { VaryHeader } from 'http-vary'import type { VaryHeader } from 'http-vary'
Quickstart
import { parse, compare, VaryHeader } from 'http-vary';
// Parse a Vary header string into a normalized array of header names.
const rawHeader: string = 'Accept-Encoding, User-Agent';
const vary: VaryHeader = parse(rawHeader);
console.log('Parsed Vary header:', vary); // => ['accept-encoding', 'user-agent']
// Handle the wildcard Vary header, which means the response varies by everything.
const wildcardVary: VaryHeader = parse('*');
console.log('Parsed wildcard Vary header:', wildcardVary); // => '*'
// Define two sets of request headers to compare for cache equivalence.
const headers1 = {
'Accept-Encoding': 'gzip',
'User-Agent': 'Chrome/120.0'
};
const headers2 = {
'Accept-Encoding': 'gzip',
'User-Agent': 'Chrome/120.0',
'Cookie': 'session=abc' // This header should be ignored if not in the Vary list
};
// Compare headers for cache equivalence based on the parsed Vary header.
const isEquivalent1: boolean = compare(vary, headers1, headers2);
console.log('Headers 1 and 2 are equivalent (Accept-Encoding, User-Agent):', isEquivalent1); // true
const headers3 = {
'Accept-Encoding': 'br',
'User-Agent': 'Firefox/120.0'
};
const isEquivalent2: boolean = compare(vary, headers1, headers3);
console.log('Headers 1 and 3 are equivalent (Accept-Encoding, User-Agent):', isEquivalent2); // false (different values)
const headers4 = {
'Accept-Encoding': 'gzip',
'User-Agent': 'Chrome/121.0'
};
const isEquivalent3: boolean = compare(wildcardVary, headers1, headers4);
console.log('Headers 1 and 4 are equivalent (*):', isEquivalent3); // false (wildcard makes even minor changes relevant)