The NodeSource Blog

Request is going into maintenance mode, this is what you need to know

Request is the most popular simplified HTTP request client for Node.js, and it was one of the first modules added to the npm registry. Designed to be the simplest way possible to make HTTP calls in Node.js, It has +14 million downloads per week. It supports HTTPS and follows redirects by default.

On March 30th 2019, it was announced that request will go into maintenance mode and stop considering new features or major releases.

Screen Shot 2019-04-01 at 2.15.10 PM

So, if this library is so popular, why did the contributors decided to stop supporting it? What are the implications for the Node.js developer ecosystem? And most importantly, what are the best-supported alternatives out there?

Let’s start with the beginning:

What Does Request Do (and, What is an HTTP Request)?

HTTP stands for Hypertext Transfer Protocol, and the main purpose is to structure request (a user’s petition to a server) and responses (the data returning to the user) over the internet. HTTP requires data to be transferred from one point to another over the network.

HTTP-Request-and-Response-Over-Web-1

Request and other libraries were created to handle HTTP calls in a simple way, because even if the HTTP native module of Node.js can handle the HTTP calls, it is more difficult to configure and can introduce a lot of complexity to a project (simple things like configuring HTTP to connect to a proxy, or making a POST request, can get very complicated).

Why Request is going into Maintenance Mode (and what is maintenance mode?)

For a popular module like request, maintenance mode means that the contributors will keep supporting the code, fixing minor bugs, refactoring, and making other minor changes, but they will not work extensively on creating new features, or major releases. In other words, the project will stop evolving.

This happens in part because JavaScript and Node.js have evolved a lot; new patterns have emerged becoming standard for most developers.

However, in this specific case the patterns at the core of request are out of date. For example, most people use async/await to work with promises. This pattern was first introduced to Node.js in version 8, but request doesn’t support it. And since request remains one of the most depended-on modules in the registry, creating a major change in the patterns would affect the more than 41,000 modules which depend on this module, as well as, thousands of blog posts and StackOverflow responses.

In short, major changes to request would result in a lot of conflicts. That’s why the contributors to request opted to let the code and the community to outgrow the module organically, and adopt other JavaScript modules that include the new patterns for the best interest of the community.

A version of the request module written including these new language patterns is effectively an entirely different module altogether, and it will be easier to create a brand new module than to try to adapt request with radically new patterns. There are modules that already take into account the new JavaScript patterns, so it seems the best option to follow.

As was pointed by Mikeal Rogers in this issue “The place request has in the Node.js ecosystem is no longer one of an innovator but of an incumbent.

It’s much harder for new libraries accomplishing similar tasks to gain adoption because of the incumbent position request holds over the ecosystem.

...The best thing for these new modules is for request to slowly fade away, eventually becoming just another memory of that legacy stack. Taking the position request has now and leveraging it for a bigger share of the next generation of developers would be a disservice to those developers as it would drive them away from better modules that don’t have the burden of request’s history”.

Implications on the community

When a project such as request with +22,000 stars on GitHub, +280 contributors, and 144 releases, goes into maintenance mode, it usually means that the technology will become outdated soon, and people need to identify more current alternatives.

Alternatives to Request

As a starting point, here’s a list of good alternatives to replace request, all of which rely on the new, post-Node.js 8.x patterns:

Needle, Client Request, Bent, R2, Hyperquest and make-fetch-happen.

But in this blog post, we will focus on the most popular ones

In the following table, we can visualize the comparison between the 5 modules and the most important features of each of them, such as size, HTTP/2 and browser support, promise and stream API, request cancellation, cookies, hooks, module dependencies, and issues.

Screen Shot 2019-04-02 at 10.16.06 PM

Got

Got is a human-friendly and powerful HTTP request library.

It supports redirects, promises, streams, retries, handling gzip/deflate, advanced timeouts and some convenience options.

According to the documentation, Got was created because request is bloated (it has several megabytes! 4.46 MB compared to 302 KB of got).

Popularity

Install

$ npm install got

Usage

const got = require('got');

(async () => {
    try {
        const response = await got('https://www.nodesource.com/');
        console.log(response.body);
        //=> '<!doctype html> ...'
    } catch (error) {
        console.log(error.response.body);
        //=> 'Internal server error ...'
    }
})();

In this example we can see the usage of async/await and how it catches errors.

Errors

Each error contains host, hostname, method, path, protocol, url and gotOptions properties to make debugging easier.

In Promise mode, the response is attached to the error.

Pros:

Compared to the other modules, got is the one that supports more features and is gaining a lot of popularity because is user-friendly, has a small installation size, and it’s up to date will all JavaScript new patterns.

Cons:

It doesn’t have browser support.

Axios

Promise-based HTTP client for the browser and Node.js

Popularity

Install

$ npm install axios

Usage

const axios = require('axios');

// Make a request for a user with a given ID
axios.get('https://www.nodesource.com/')
  .then(function (response) {
    // handle success
    console.log(response);
  })
  .catch(function (error) {
    // handle error
    console.log(error);
  })
  .then(function () {
    // always executed
  });

// Using async/await
async function getUser() {
  try {
    const response = await axios.get('https://www.nodesource.com/');
    console.log(response);
  } catch (error) {
    console.error(error);
  }
}

In the example above we can see a basic GET request, in a traditional way and using async/await.

Errors

This is how axios handles errors:

axios.get('https://www.nodesource.com/')
  .catch(function (error) {
    if (error.response) {
      // The request was made and the server responded with a status code
      // that falls out of the range of 2xx
      console.log(error.response.data);
      console.log(error.response.status);
      console.log(error.response.headers);
    } else if (error.request) {
      // The request was made but no response was received
      // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
      // http.ClientRequest in node.js
      console.log(error.request);
    } else {
      // Something happened in setting up the request that triggered an Error
      console.log('Error', error.message);
    }
    console.log(error.config);
  });

You can define a custom HTTP status code error range using the validateStatus config option.

Pros

Axios lets you fully set up and configure your requests by simply passing a single configuration object to it. It performs automatic transformations of JSON data and has the ability to monitor POST request progress.

Axios is also the most widely used module for HTTP request in the front-end. Is very popular and follows the newest patterns of JavaScript. It handles request cancelation, follows redirects, Handles gzip/deflate, hooks and errors with metadata.

Cons

Axios doesn’t support HTTP2, electron and Stream API. It also doesn’t retry on failures and works on Node.js with prebuilt promise support. Older version requires Bluebird or Q promise.

Node Fetch

A light-weight module that brings window.fetch to Node.js

Popularity

Install

$ npm install node-fetch --save

Usage

Plain text or HTML

fetch('https://www.nodesource.com/')
    .then(res => res.text())
    .then(body => console.log(body));

Simple Post

fetch('https://www.nodesource.com/', { method: 'POST', body: 'a=1' })
    .then(res => res.json()) // expecting a json response
    .then(json => console.log(json));

Errors

Simple error handling:

fetch('https://www.invalid.nodesource.com/')
    .catch(err => console.error(err));

It is common to create a helper function to check that the response contains no client (4xx) or server (5xx) error responses:

function checkStatus(res) {
    if (res.ok) { // res.status >= 200 && res.status < 300
        return res;
    } else {
        throw MyCustomError(res.statusText);
    }
}

fetch('https://www.nodesource.com/')
    .then(checkStatus)
    .then(res => console.log('will not get here...'))

Pros

Node-fetch is the most lightweight module for HTTP requests at just 150 KB install size. It has cool features which allow you to substitute its promise library or decode modern web encoding as gzip/deflate, it has JSON mode, browser support, promise API and request cancellation. It follows the latest JavaScript patterns of HTTP request and is the most popular module after request, with almost 8 million downloads per week (surpassing Axios, Got and Superagent).

Cons

It doesn’t have HTTP/2 and cookies support, RFC compliant caching and it doesn’t retry on failure. Also doesn’t support progress events, advanced timeouts, errors with metadata and hooks.

Superagent

Small progressive client-side HTTP request library, and Node.js module with the same API sporting many high-level HTTP client features.

Popularity

Install

$ npm install superagent

Usage

const superagent = require('superagent');

// callback
superagent
  .post('/api/pet')
  .send({ name: 'Manny', species: 'cat' }) // sends a JSON post body
  .set('X-API-Key', 'foobar')
  .set('accept', 'json')
  .end((err, res) => {
    // Calling the end function will send the request
  });

// promise with then/catch
superagent.post('/api/pet').then(console.log).catch(console.error);

// promise with async/await
(async () => {
  try {
    const res = await superagent.post('/api/pet');
    console.log(res);
  } catch (err) {
    console.error(err);
  }
})();

In the example above we can see how Superagent handles errors as well as promises with both callbacks and with async/await.

Pros

Superagent is very well-known, it provides a fluent interface for making HTTP requests, a plugin architecture, and numerous plugins already available for many common features (for example, superagent prefix to add a prefix to all URLs).

Superagent also has promise and stream API, request cancellation, it retries when there is a failure, it has progress events and handles gzip/deflate.

Cons

The build of Superagent is currently failing. Also, it doesn’t support monitoring upload progress like XMLHttpRequest.

It doesn’t support timings, errors with metadata, or hooks.

The NodeSource platform offers a high-definition view of the performance, security and behavior of Node.js applications and functions.

Start for Free