Coder Social home page Coder Social logo

bricss / rekwest Goto Github PK

View Code? Open in Web Editor NEW
24.0 3.0 0.0 1.68 MB

The robust request library that humanity deserves ๐ŸŒ

Home Page: https://www.npmjs.com/package/rekwest

JavaScript 99.82% Shell 0.18%
http http2 nodejs http-client http-request http2-client http2-request multipart multipart-formdata multipart-uploads

rekwest's Introduction

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 Cookies treatment (with built-in jar & ttl)
  • Automatic decompression (with opt-in body compression)
  • Built-in streamable FormData interface
  • Support redirects & retries with fine-grained tune-ups
  • Support all legit request body types (include blobs & streams)
  • Support both CJS and ESM module systems
  • Fully promise-able and pipe-able
  • Zero dependencies

Prerequisites

  • Node.js >= 18.13.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 compression
    /** [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,
  Blob,
  File,
  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.dab');
const readable = Readable.from('bits');

const fd = new FormData({
  aux: Date.now(),  // either [[key, value]] or kv sequenceable
});

fd.append('celestial', 'payload');
fd.append('blob', blob, 'blob.dab');
fd.append('file', file);
fd.append('readable', readable, 'readable.dab');

const url = 'https://somewhe.re/somewhat/endpoint';

const res = await rekwest(url, {
  body: fd,
  headers: {
    [HTTP2_HEADER_AUTHORIZATION]: 'Bearer [token]',
    [HTTP2_HEADER_CONTENT_ENCODING]: 'br',  // enables: body compression
  },
  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
    • baseURL {string | URL} The base URL to use in cases where url is 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
    • cookies {boolean | Array<[k, v]> | Array<string> | Cookies | Object | URLSearchParams} Default: true The cookies to add to the request
    • cookiesTTL {boolean} Default: false Controls enablement of TTL for the cookies cache
    • credentials {include | omit | same-origin} Default: same-origin Controls credentials in case of cross-origin redirects
    • digest {boolean} Default: true Controls whether to read the response stream or simply add a mixin
    • follow {number} Default: 20 The number of redirects to follow
    • h2 {boolean} Default: false Forces the use of HTTP/2 protocol
    • headers {Object} The headers to add to the request
    • maxRetryAfter {number} The upper limit of retry-after header. If unset, it will use timeout value
    • parse {boolean} Default: true Controls whether to parse response body or simply return a buffer
    • redirect {error | follow | manual} Default: follow Controls the redirect flows
    • retry {Object} Represents the retry options
      • attempts {number} Default: 0 The number of retry attempts
      • backoffStrategy {string} Default: interval * Math.log(Math.random() * (Math.E * Math.E - Math.E) + Math.E) The backoff strategy algorithm that increases logarithmically. To fixate set value to interval * 1
      • errorCodes {string[]} Default: ['EAI_AGAIN', 'ECONNREFUSED', 'ECONNRESET', 'EHOSTDOWN', 'EHOSTUNREACH', 'ENETDOWN', 'ENETUNREACH', 'ENOTFOUND', 'EPIPE', 'ERR_HTTP2_STREAM_ERROR'] The list of error codes to retry on
      • interval {number} Default: 1e3 The initial retry interval
      • retryAfter {boolean} Default: true Controls retry-after header receptiveness
      • statusCodes {number[]} Default: [429, 500, 502, 503, 504] The list of status codes to retry on
    • stripTrailingSlash {boolean} Default: false Controls whether to strip trailing slash at the end of the URL
    • thenable {boolean} Default: false Controls the promise resolutions
    • timeout {number} Default: 3e5 The number of milliseconds a request can take before termination
    • trimTrailingSlashes {boolean} Default: false Controls whether to trim trailing slashes within the URL
  • Returns: Promise that resolves to extended http.IncomingMessage or http2.ClientHttp2Stream which is 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 if parse: false
      • json {AsyncFunction} Reads the response and returns Object
      • text {AsyncFunction} Reads the response and returns String
    • bodyUsed {boolean} Indicates whether the response were 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 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

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 signal = AbortSignal.timeout(1e4);
const url = '/somewhat/endpoint';

const res = await rk(url, {
  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: true in options to use HTTP/2 protocol
    • Use ackn({ url: URL }) method in advance to check the available protocols
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.

rekwest's People

Contributors

bricss avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

rekwest's Issues

does not work with node 16.4.x

package.json and README lists engine compatibility as 16.x that is false

node --version
v16.4.0
import rekwest, { constants } from 'rekwest';

const {
  HTTP2_HEADER_AUTHORIZATION,
  HTTP2_HEADER_CONTENT_ENCODING,
  HTTP2_METHOD_POST,
  HTTP_STATUS_OK,
} = constants;

const url = 'http://localhost:6666';

const res = await rekwest(url, {
  body: { celestial: 'payload' },
  headers: {
    [HTTP2_HEADER_AUTHORIZATION]: 'Bearer [token]',
    [HTTP2_HEADER_CONTENT_ENCODING]: 'br',
  },
  method: HTTP2_METHOD_POST,
});

console.assert(res.statusCode === HTTP_STATUS_OK);
console.info(res.headers);
console.log(res.body);

node r.mjs

file:///Users/m/xxx/node_modules/rekwest/src/formdata.mjs:3
import { toUSVString } from 'util';
         ^^^^^^^^^^^
SyntaxError: The requested module 'util' does not provide an export named 'toUSVString'
    at ModuleJob._instantiate (node:internal/modules/esm/module_job:121:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:171:5)
    at async Loader.import (node:internal/modules/esm/loader:178:24)
    at async Object.loadESM (node:internal/process/esm_loader:68:5)
    at async handleMainPromise (node:internal/modules/run_main:63:12)

Upgrading node to 16.13.x fixes the issue.
Please change documentation or make it backward compatible.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.