headers
is a toolkit for working with HTTP headers in JavaScript.
HTTP headers contain a wealth of information:
- Who is sending this request?
- What's in the payload and how is it encoded?
- What is the filename of this file upload?
- and much more!
The built-in JavaScript Headers
interface accepts and gives you strings for everything, which you're probably used to parsing and stringifying manually as needed. This library aims to give you a more fluent interface for all of this information. Similar to how the DOM gives you programmatic access to HTML documents, headers
gives you access to HTTP headers.
npm install @mjackson/headers
The following should give you a sense of what kinds of things you can do with this library:
import Headers from '@mjackson/headers';
let headers = new Headers();
// Accept
headers.accept = 'text/html, text/*;q=0.9';
headers.accept.mediaTypes; // [ 'text/html', 'text/*' ]
Object.fromEntries(headers.accept.entries()); // { 'text/html': 1, 'text/*': 0.9 }
headers.accept.accepts('text/html'); // true
headers.accept.accepts('text/plain'); // true
headers.accept.accepts('image/jpeg'); // false
headers.accept.getPreferred(['text/plain', 'text/html']); // 'text/html'
headers.accept.set('text/plain', 0.9);
headers.accept.set('text/*', 0.8);
headers.get('Accept'); // 'text/html,text/plain;q=0.9,text/*;q=0.8'
// Accept-Encoding
headers.acceptEncoding = 'gzip, deflate;q=0.8';
headers.acceptEncoding.accepts('gzip'); // true
headers.acceptEncoding.accepts('br'); // false
headers.acceptEncoding.getPreferred(['gzip', 'deflate']); // 'gzip'
// Accept-Language
headers.acceptLanguage = 'en-US, en;q=0.9';
headers.acceptLanguage.languages; // [ 'en-us', 'en' ]
Object.fromEntries(headers.acceptLanguage.entries()); // { 'en-us': 1, en: 0.9 }
headers.acceptLanguage.accepts('en'); // true
headers.acceptLanguage.accepts('ja'); // false
headers.acceptLanguage.getPreferred(['en-US', 'en-GB']); // 'en-US'
headers.acceptLanguage.getPreferred(['en', 'fr']); // 'en'
// Accept-Ranges
headers.acceptRanges = 'bytes';
// Connection
headers.connection = 'close';
// Content-Type
headers.contentType = 'application/json; charset=utf-8';
headers.contentType.mediaType; // "application/json"
headers.contentType.charset; // "utf-8"
headers.contentType.charset = 'iso-8859-1';
headers.get('Content-Type'); // "application/json; charset=iso-8859-1"
// Content-Disposition
headers.contentDisposition =
'attachment; filename="example.pdf"; filename*=UTF-8\'\'%E4%BE%8B%E5%AD%90.pdf';
headers.contentDisposition.type; // 'attachment'
headers.contentDisposition.filename; // 'example.pdf'
headers.contentDisposition.filenameSplat; // 'UTF-8\'\'%E4%BE%8B%E5%AD%90.pdf'
headers.contentDisposition.preferredFilename; // '例子.pdf'
// Cookie
headers.cookie = 'session_id=abc123; user_id=12345';
headers.cookie.get('session_id'); // 'abc123'
headers.cookie.get('user_id'); // '12345'
headers.cookie.set('theme', 'dark');
headers.get('Cookie'); // 'session_id=abc123; user_id=12345; theme=dark'
// Host
headers.host = 'example.com';
// Last-Modified
headers.lastModified = new Date();
// or headers.lastModified = new Date().getTime();
headers.get('Last-Modified'); // 'Fri, 20 Dec 2024 08:08:05 GMT'
// Location
headers.location = 'https://example.com';
// Referer
headers.referer = 'https://example.com/';
// Set-Cookie
headers.setCookie = ['session_id=abc123; Path=/; HttpOnly'];
headers.setCookie[0].name; // 'session_id'
headers.setCookie[0].value; // 'abc123'
headers.setCookie[0].path; // '/'
headers.setCookie[0].httpOnly; // true
// Modifying Set-Cookie attributes
headers.setCookie[0].maxAge = 3600;
headers.setCookie[0].secure = true;
headers.get('Set-Cookie'); // 'session_id=abc123; Path=/; HttpOnly; Max-Age=3600; Secure'
// Setting multiple cookies is easy, it's just an array
headers.setCookie.push('user_id=12345; Path=/api; Secure');
// or headers.setCookie = [...headers.setCookie, '...']
// Accessing multiple Set-Cookie headers
for (let cookie of headers.getSetCookie()) {
console.log(cookie);
}
// session_id=abc123; Path=/; HttpOnly; Max-Age=3600; Secure
// user_id=12345; Path=/api; Secure
Headers
can be initialized with an object config:
let headers = new Headers({
contentType: {
mediaType: 'text/html',
charset: 'utf-8',
},
setCookie: [
{ name: 'session', value: 'abc', path: '/' },
{ name: 'theme', value: 'dark', expires: new Date('2021-12-31T23:59:59Z') },
],
});
console.log(`${headers}`);
// Content-Type: text/html; charset=utf-8
// Set-Cookie: session=abc; Path=/
// Set-Cookie: theme=dark; Expires=Fri, 31 Dec 2021 23:59:59 GMT
Headers
works just like DOM's Headers
(it's a subclass) so you can use them anywhere you need a Headers
.
import Headers from '@mjackson/headers';
// Use in a fetch()
let response = await fetch('https://example.com', {
headers: new Headers(),
});
// Convert from DOM Headers
let headers = new Headers(response.headers);
headers.set('Content-Type', 'text/html');
headers.get('Content-Type'); // "text/html"
If you're familiar with using DOM Headers
, everything works as you'd expect.
Headers
are iterable:
let headers = new Headers({
'Content-Type': 'application/json',
'X-API-Key': 'secret-key',
'Accept-Language': 'en-US,en;q=0.9',
});
for (let [name, value] of headers) {
console.log(`${name}: ${value}`);
}
// Content-Type: application/json
// X-Api-Key: secret-key
// Accept-Language: en-US,en;q=0.9
If you're assembling HTTP messages, you can easily convert to a multiline string suitable for using as a Request/Response header block:
let headers = new Headers({
'Content-Type': 'application/json',
'Accept-Language': 'en-US,en;q=0.9',
});
console.log(`${headers}`);
// Content-Type: text/html
// Accept-Language: en-US,en;q=0.9
In addition to the high-level Headers
API, headers
also provides a rich set of primitives you can use to work with just about any complex HTTP header value. Each header class includes a spec-compliant parser (the constructor), stringifier (toString
), and getters/setters for all relevant attributes. Classes for headers that contain a list of fields, like Cookie
, are iterable.
If you need support for a header that isn't listed here, please send a PR! The goal is to have first-class support for all common HTTP headers.
import { Accept } from '@mjackson/headers';
let header = new Accept('text/html;text/*;q=0.9');
header.has('text/html'); // true
header.has('text/plain'); // false
header.accepts('text/html'); // true
header.accepts('text/plain'); // true
header.accepts('text/*'); // true
header.accepts('image/jpeg'); // false
header.getPreferred(['text/html', 'text/plain']); // 'text/html'
for (let [mediaType, quality] of header) {
// ...
}
// Alternative init styles
let header = new Accept({ 'text/html': 1, 'text/*': 0.9 });
let header = new Accept(['text/html', ['text/*', 0.9]]);
import { AcceptEncoding } from '@mjackson/headers';
let header = new AcceptEncoding('gzip,deflate;q=0.9');
header.has('gzip'); // true
header.has('br'); // false
header.accepts('gzip'); // true
header.accepts('deflate'); // true
header.accepts('identity'); // true
header.accepts('br'); // true
header.getPreferred(['gzip', 'deflate']); // 'gzip'
for (let [encoding, weight] of header) {
// ...
}
// Alternative init styles
let header = new AcceptEncoding({ gzip: 1, deflate: 0.9 });
let header = new AcceptEncoding(['gzip', ['deflate', 0.9]]);
import { AcceptLanguage } from '@mjackson/headers';
let header = new AcceptLanguage('en-US,en;q=0.9');
header.has('en-US'); // true
header.has('en-GB'); // false
header.accepts('en-US'); // true
header.accepts('en-GB'); // true
header.accepts('en'); // true
header.accepts('fr'); // true
header.getPreferred(['en-US', 'en-GB']); // 'en-US'
header.getPreferred(['en', 'fr']); // 'en'
for (let [language, quality] of header) {
// ...
}
// Alternative init styles
let header = new AcceptLanguage({ 'en-US': 1, en: 0.9 });
let header = new AcceptLanguage(['en-US', ['en', 0.9]]);
import { CacheControl } from '@mjackson/headers';
let header = new CacheControl('public, max-age=3600, s-maxage=3600');
header.public; // true
header.maxAge; // 3600
header.sMaxage; // 3600
// Alternative init style
let header = new CacheControl({ public: true, maxAge: 3600 });
import { ContentDisposition } from '@mjackson/headers';
let header = new ContentDisposition('attachment; name=file1; filename=file1.txt');
header.type; // "attachment"
header.name; // "file1"
header.filename; // "file1.txt"
header.preferredFilename; // "file1.txt"
// Alternative init style
let header = new ContentDisposition({
type: 'attachment',
name: 'file1',
filename: 'file1.txt',
});
import { ContentType } from '@mjackson/headers';
let header = new ContentType('text/html; charset=utf-8');
header.mediaType; // "text/html"
header.boundary; // undefined
header.charset; // "utf-8"
// Alternative init style
let header = new ContentType({
mediaType: 'multipart/form-data',
boundary: '------WebKitFormBoundary12345',
charset: 'utf-8',
});
import { Cookie } from '@mjackson/headers';
let header = new Cookie('theme=dark; session_id=123');
header.get('theme'); // "dark"
header.set('theme', 'light');
header.delete('theme');
header.has('session_id'); // true
// Iterate over cookie name/value pairs
for (let [name, value] of header) {
// ...
}
// Alternative init styles
let header = new Cookie({ theme: 'dark', session_id: '123' });
let header = new Cookie([
['theme', 'dark'],
['session_id', '123'],
]);
import { SetCookie } from '@mjackson/headers';
let header = new SetCookie('session_id=abc; Domain=example.com; Path=/; Secure; HttpOnly');
header.name; // "session_id"
header.value; // "abc"
header.domain; // "example.com"
header.path; // "/"
header.secure; // true
header.httpOnly; // true
header.sameSite; // undefined
header.maxAge; // undefined
header.expires; // undefined
// Alternative init styles
let header = new SetCookie({
name: 'session_id',
value: 'abc',
domain: 'example.com',
path: '/',
secure: true,
httpOnly: true,
});
fetch-proxy
- Build HTTP proxy servers using the web fetch APInode-fetch-server
- Build HTTP servers on Node.js using the web fetch API
See LICENSE