npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

request-dot-js

v3.2.4

Published

A ~1kB fetch wrapper with convenient error handling, automatic JSON transforms, and support for exponential backoff.

Downloads

249

Readme

request.js

NPM npm bundle size (minified + gzip)

A ~1kB wrapper around fetch with convenient error handling, automatic JSON transforms, and support for request timeouts and exponential backoff.

It works in the browser, on the server (Node.js), and mobile apps (like React Native), has no dependencies, and ships with TypeScript declarations.

Installation

npm i request-dot-js or yarn add request-dot-js.

Usage

API: async request(url[, options])

import request from 'request-dot-js'

// in an async function...

const { data, type, headers, status, statusText, url } = await request('https://httpbin.org/get', {
  headers: { 'Custom-Header': 'abcd' },
  params: { a: 'b', c: 'd' }, // query params
})

if (type === 'success') handleSuccess(data)

if (type === 'error') handleError(data)

if (type === 'exception') handleException(data)

For all responses returned by request.js, type is either 'success', 'error' or 'exception'.

If no exception is thrown, data is read from the response stream. If status < 300 type is 'success'. If status >= 300, type is 'error'.

If there's a connection error, timeout, or other exception, type is 'exception', and data is the exception thrown by fetch.

The other properties come from the Response object returned by fetch:

  • status: 200, 204, etc...
  • statusText: 'OK', 'CREATED', etc...
  • url: url after redirect(s)
  • headers: object literal instead of Headers instance; header names are lowercased

If type is 'exception', these properties are undefined.

JSON by default

request.js is built for easy interaction with JSON APIs, the de facto standard for data exchange on the web.

If you pass an object literal or an array for options.body, request adds the 'content-type': 'application/json' request header and JSON stringifies the body.

By default, request also adds the 'accept': 'application/json' request header and tries to return parsed JSON for data. If you don't want it to do this, pass jsonOut: false in options, and it will return the fetch Response object for data instead.

const { data, type, ...rest } = await request('https://httpbin.org/post', {
  method: 'POST', // default method is 'GET'
  body: { a: 'b', c: 'd' }, // object body automatically passed to JSON.stringify
})
if (type === 'success') console.log(data.url) // data is parsed JSON by default
const { data, type } = await request('https://httpbin.org/post', { jsonOut: false })
if (type === 'success') {
  const blob = await data.blob()
  console.log(blob)
}

Retries with exponential backoff

import request from 'request-dot-js'

// retry request up to 5 times, with 1s, 2s, 4s, 8s and 16s delays between retries
const { data, type, ...rest } = await request('https://httpbin.org/get', {
  params: { a: 'b', c: 'd' },
  retry: { retries: 5, delay: 1000 },
})

// shouldRetry function
const { data, type, ...rest } = await request('https://httpbin.org/get', {
  retry: {
    shouldRetry: (response, { retries, delay }) => {
      console.log(retries, delay) // do something with current retries and delay if you want
      return response.type === 'exception' || response.status === 500
    },
  },
})

The options parameter has a special retry key that can point to an object with retry options:

  • retries
  • delay (in ms)
  • multiplier (default 2)
  • shouldRetry (default response => response.type === 'exception')

If you pass a retry object, and your request throws an exception, request.js retries it up to retries times and backs off exponentially.

If on any retry you regain connectivity and type is 'success' or 'error' instead of 'exception', the request method stops retrying your request and returns the usual { data, type, ...rest }.

If you want to set a custom condition for when to retry a request, pass your own shouldRetry function. It receives the usual response, { data, type, ...rest }, and the current backoff values, { retries, delay }. If it returns a falsy value request.js stops retrying your request.

The shouldRetry function also lets you react to individual retries before request is done executing all of them, if you want to do that. See the example above.

Request timeout / aborting a request

Little known fact, but this is actually easy to do with fetch, it's just not supported on older browsers.

The options parameter has a special timeout key. If a timeout is specified, request.js aborts the request after timeout ms, and returns an exception response.

const { data, type } = await request('https://httpbin.org/get', { timeout: 1 })
// time out after 1ms -- type will be 'exception'

Convenience methods

request.js has convenience methods for the following HTTP methods: DELETE, GET, HEAD, OPTIONS, PATCH, POST, and PUT.

import request from 'request-dot-js'

const { data, type } = await request.delete('https://httpbin.org/delete')

const { data, type } = await request.put('https://httpbin.org/put', { body: { a: 'b' } })

These allow you to send non-GET requests without passing the method key in options.

Query stringification

request.js comes with a function that converts a query params object to a query string. If you want a fancier stringify function, like the one in qs, you can pass your own in options.

import qs from 'qs'

const { data, type } = await request('https://httpbin.org/get', { params: { a: 'b' }, stringify: qs.stringify })

TypeScript

request.js works great with TypeScript (it's written in TypeScript). Check out examples here.

Make sure you enable esModuleInterop if you're using TypeScript to compile your application. This option is enabled by default if you run tsc --init.

Regarding convenience methods, you can't do this:

import request from 'request-dot-js'

request.put(...)

Do this instead:

import { put } from 'request-dot-js'

put(...)

Also, you can't do this, because delete is a restricted keyword:

import { delete as del } from 'request-dot-js'

Do this instead:

import { del } from 'request-dot-js'

On the server

request.js ships with a module that works in the browser, index.js, and a module that works on the server, server.js. If you're using it on the server, make sure to import everything from server.js.

import request from 'request-dot-js/server'

Why request.js?

Why not axios, or just fetch? Unlike fetch, request.js is very convenient to use:

  • automatic JSON transforms
  • query params and response headers as object literals
  • no double await to read data
  • automatically removes body for GET and HEAD requests

And unlike either of them, it doesn't require try / catch to handle exceptions. const { data, type } = await request(...) has all the info you need to handle successful requests, request errors, connection errors, and request timeouts.

This design leads to another feature the others don't have: flexible, built-in support for retries with exponential backoff.

Dependencies

For modern browsers, or React Native, request.js has no dependencies.

If you're targeting older browsers, like Internet Explorer, you need to polyfill fetch and Promise, and use Babel to transpile your code.

If you use request.js on the server, node-fetch and abort-controller are the only dependencies.

Development and tests

Clone the repo, then yarn, then yarn test.