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.
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.
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.
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
- +6.2 MM npm weekly downloads
- +5K GitHub stars
- 71 contributors
- +2.5K Modules that depend on got
- +280 Forks
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
- +4.4 MM npm weekly downloads
- +57K GitHub stars
- 71 contributors
- +15.6K Modules that depend on axios
- +4.4K Forks
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
- ~8 MM npm weekly downloads
- 3.8K GitHub stars
- 38 contributors
- +6.8K Modules that depend on axios
- +383 Forks
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
- 2.5 MM npm weekly downloads
- +14K stars on GitHub
- 182 contributors
- +6.4K Modules that depend on axios
- +1.2K Forks
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.