The robust request library that humanity deserves 🌐
This package provides highly likely functional and easy-to-use abstraction atop of native http(s).request and http2.request.
Abstract
- Fetch-alike 🥏
- Cool-beans 🫛 config options (with defaults) 📋
- Automatic HTTP/2 support (ALPN negotiation) 💼
- Automatic or opt-in body parse (with non-UTF-8 charset decoding) 🉑
- Automatic and simplistic
Cookiestreatment (with TTL support) 🍪 - Automatic body decoding (and opt-in request body encoding) 🗜️
- Better error management 🚥
- Built-in streamable
FormDatainterface 🔌 - Support certificate pinning for enhanced TLS security 🛡️
- Support redirects & retries with fine-grained tune-ups 🪛
- Support plenty request body types (include blobs & streams) 📦
- Support both CJS and ESM module systems 🧩
- Fully promise-able ⏳ and pipe-able 🌀
- Zero dependencies 🗽
Prerequisites
- Node.js
>=22.0.0
Installation
npm install rekwest --save
Usage
import rekwest, { constants } from 'rekwest'; const { HTTP2_HEADER_AUTHORIZATION, HTTP2_HEADER_CONTENT_ENCODING, HTTP2_METHOD_POST, HTTP_STATUS_OK, } = constants; const url = 'https://somewhe.re/somewhat/endpoint'; const res = await rekwest(url, { body: { celestial: 'payload' }, headers: { [HTTP2_HEADER_AUTHORIZATION]: 'Bearer [token]', [HTTP2_HEADER_CONTENT_ENCODING]: 'br', // Enables: body encoding /** * [HTTP2_HEADER_CONTENT_TYPE] is undue for * Array/Blob/File/FormData/Object/URLSearchParams body types * and will be set automatically, with an option to override it here. */ }, method: HTTP2_METHOD_POST, }); console.assert(res.statusCode === HTTP_STATUS_OK); console.info(res.headers); console.log(res.body);
import { Readable } from 'node:stream'; import rekwest, { constants, FormData, } from 'rekwest'; const { HTTP2_HEADER_AUTHORIZATION, HTTP2_HEADER_CONTENT_ENCODING, HTTP2_METHOD_POST, HTTP_STATUS_OK, } = constants; const blob = new Blob(['bits']); const file = new File(['bits'], 'file.xyz'); const rbl = Readable.from('bits'); const rds = ReadableStream.from('bits'); const fd = new FormData({ aux: new Date(), // Either [[key, value]] or kv sequenceable }); fd.append('celestial', 'payload'); fd.append('blob', blob, 'blob.xyz'); fd.append('file', file); fd.append('rbl', rbl, 'rbl.xyz'); fd.append('rds', rds, 'rds.xyz'); /** * Streamable entries are consumed on request submittion. */ const url = 'https://somewhe.re/somewhat/endpoint'; const res = await rekwest(url, { body: fd, headers: { [HTTP2_HEADER_AUTHORIZATION]: 'Bearer [token]', [HTTP2_HEADER_CONTENT_ENCODING]: 'zstd', // Enables: body encoding }, method: HTTP2_METHOD_POST, }); console.assert(res.statusCode === HTTP_STATUS_OK); console.info(res.headers); console.log(res.body);
API
rekwest(url[, options])
-
url{string | URL} The URL to send the request to. -
options{Object} Extends http(s).RequestOptions along with extra http2.ClientSessionOptions & http2.ClientSessionRequestOptions and tls.ConnectionOptions for HTTP/2 attunes.-
allowDowngrade{boolean}Default: falseControls whetherhttps:redirects tohttp:are allowed. -
baseURL{string | URL} The base URL to use in cases whereurlis a relative URL. -
body{string | Array | ArrayBuffer | ArrayBufferView | AsyncIterator | Blob | Buffer | DataView | File | FormData | Iterator | Object | Readable | ReadableStream | SharedArrayBuffer | URLSearchParams} The body to send with the request. -
bufferBody{boolean}Default: falseToggles the buffering of the streamable request bodies for redirects and retries. -
certPins{string[]}Default: []A list of SHA-256 certificate fingerprints (colon-separated hex) used for HTTPS certificate pinning. If the list is non-empty and none of the fingerprints match, the connection will be rejected. -
cookies{boolean | string | string[] | [k, v][] | Cookies | Object | URLSearchParams}Default: trueThe cookies to add to the request. Manually setcookieheader to override. -
cookiesTTL{boolean}Default: falseControls enablement of TTL for the cookie cache. -
credentials{'include' | 'omit' | 'same-origin'}Default: 'same-origin'Controls credentials in case of cross-origin redirects. -
decodersOptions{Object} Configures decoder options, e.g.:brotli,zlib,zstd. -
digest{boolean}Default: trueControls whether to read the response stream or add a mixin. -
encodersOptions{Object} Configures encoder options, e.g.:brotli,zlib,zstd. -
follow{number}Default: 20The number of redirects to follow. -
h2{boolean}Default: falseForces the use of HTTP/2 protocol. -
headers{Object} The headers to add to the request. -
params{Object} The search params to add to theurl. -
parse{boolean}Default: trueControls whether to parse the response body or return a buffer. -
redirect{'error' | 'follow' | 'manual'}Default: 'follow'Controls the redirect flows. -
retry{Object} Represents the retry options.-
attempts{number}Default: 0The number of retry attempts. -
backoffStrategy{string}Default: 'interval * Math.log(Math.random() * (Math.E * Math.E - Math.E) + Math.E)'The backoff strategy uses a log-uniform algorithm. Evaluated in a sandboxed VM context. To fix the interval, set the value to'interval * 1'. -
errorCodes{string[]}Default: ['ECONNREFUSED', 'ECONNRESET', 'EHOSTDOWN', 'EHOSTUNREACH', 'ENETDOWN', 'ENETUNREACH', 'ENOTFOUND', 'ERR_HTTP2_STREAM_ERROR']The list of error codes to retry on. -
interval{number}Default: 1e3The initial retry interval. -
maxRetryAfter{number}Default: 3e5The maximumretry-afterlimit in milliseconds. -
retryAfter{boolean}Default: trueControlsretry-afterheader receptiveness. -
statusCodes{number[]}Default: [429, 500, 502, 503, 504]The list of status codes to retry on.
-
-
stripTrailingSlash{boolean}Default: falseControls whether to strip trailing slash at the end of the URL. -
thenable{boolean}Default: falseControls the promise resolutions. -
timeout{number}Default: 3e5The number of milliseconds a request can take before termination. -
trimTrailingSlashes{boolean}Default: falseControls whether to trim trailing slashes within the URL.
-
-
Returns: Promise that resolves to
extended http.IncomingMessage
or http2.ClientHttp2Stream which are respectively
readable and duplex streams.
- if
digest: true&parse: true-
body{string | Array | Buffer | Object} The body based on its content type.
-
- if
digest: false-
arrayBuffer{AsyncFunction} Reads the response and returns ArrayBuffer. -
blob{AsyncFunction} Reads the response and returns Blob. -
body{AsyncFunction} Reads the response and returns Buffer ifparse: false. -
bytes{AsyncFunction} Reads the response and returns Uint8Array. -
json{AsyncFunction} Reads the response and returns Object. -
text{AsyncFunction} Reads the response and returns String.
-
-
bodyUsed{boolean} Indicates whether the response was read or not. -
cookies{undefined | Cookies} The cookies sent and received with the response. -
headers{Object} The headers received with the response. -
httpVersion{string} Indicates a protocol version negotiated with the server. -
ok{boolean} Indicates if the response was successful (statusCode: 200-299). -
redirected{boolean} Indicates if the response is the result of a redirect. -
statusCode{number} Indicates the status code of the response. -
trailers{undefined | Object} The trailer headers received with the response.
- if
rekwest.defaults
The object to fulfill with default options.
rekwest.extend(options)
The method to extend default options per instance.
import rekwest, { constants } from 'rekwest'; const { HTTP_STATUS_OK, } = constants; const rk = rekwest.extend({ baseURL: 'https://somewhe.re', }); const params = { id: '[uid]', signature: '[code]', variant: '[any]', }; const signal = AbortSignal.timeout(3e4); const url = '/somewhat/endpoint'; const res = await rk(url, { params, signal, }); console.assert(res.statusCode === HTTP_STATUS_OK); console.info(res.headers); console.log(res.body);
rekwest.stream(url[, options])
The method with limited functionality to use with streams and/or pipes.
- No automata (redirects & retries).
- Pass
h2: truein options to use HTTP/2 protocol.- Use
ackn({ url: URL })method in advance to check the available protocols.
- Use
import fs from 'node:fs'; import { pipeline } from 'node:stream/promises'; import rekwest, { ackn, constants, } from 'rekwest'; const { HTTP2_METHOD_POST, } = constants; const url = new URL('https://somewhe.re/somewhat/endpoint'); const options = await ackn({ url }); await pipeline( fs.createReadStream('/path/to/read/inlet.xyz'), rekwest.stream(url, { ...options, method: HTTP2_METHOD_POST }), fs.createWriteStream('/path/to/write/outlet.xyz'), );
For more details, please check tests (coverage: >97%) in the repository.