What is popsicle?
Popsicle is a versatile HTTP request library for Node.js and the browser. It provides a simple and consistent API for making HTTP requests, handling responses, and managing various aspects of HTTP communication such as headers, query parameters, and request/response bodies.
What are popsicle's main functionalities?
Making HTTP Requests
This feature allows you to make HTTP requests to a specified URL. The example demonstrates a GET request to a JSON placeholder API, logging the status and body of the response.
const { request } = require('popsicle');
request('https://jsonplaceholder.typicode.com/posts/1')
.then(response => {
console.log(response.status);
console.log(response.body);
})
.catch(error => {
console.error(error);
});
Handling Query Parameters
This feature allows you to include query parameters in your HTTP requests. The example demonstrates a GET request with a query parameter to filter posts by userId.
const { request } = require('popsicle');
request({
url: 'https://jsonplaceholder.typicode.com/posts',
query: { userId: 1 }
})
.then(response => {
console.log(response.status);
console.log(response.body);
})
.catch(error => {
console.error(error);
});
Setting Headers
This feature allows you to set custom headers for your HTTP requests. The example demonstrates setting the 'Content-Type' header to 'application/json'.
const { request } = require('popsicle');
request({
url: 'https://jsonplaceholder.typicode.com/posts',
headers: { 'Content-Type': 'application/json' }
})
.then(response => {
console.log(response.status);
console.log(response.body);
})
.catch(error => {
console.error(error);
});
Handling Request and Response Bodies
This feature allows you to handle request and response bodies. The example demonstrates a POST request with a JSON body to create a new post.
const { request } = require('popsicle');
request({
method: 'POST',
url: 'https://jsonplaceholder.typicode.com/posts',
body: { title: 'foo', body: 'bar', userId: 1 },
headers: { 'Content-Type': 'application/json' }
})
.then(response => {
console.log(response.status);
console.log(response.body);
})
.catch(error => {
console.error(error);
});
Other packages similar to popsicle
axios
Axios is a popular promise-based HTTP client for the browser and Node.js. It provides a simple API for making HTTP requests and handling responses, similar to Popsicle. Axios is known for its ease of use and wide adoption in the JavaScript community.
node-fetch
Node-fetch is a lightweight module that brings `window.fetch` to Node.js. It is a minimalistic library that provides a simple API for making HTTP requests, similar to the Fetch API in the browser. Node-fetch is often used for its simplicity and compatibility with the Fetch API standard.
superagent
Superagent is a small progressive client-side HTTP request library, and Node.js module with a similar API. It provides a flexible and powerful API for making HTTP requests and handling responses. Superagent is known for its extensive feature set and ease of use.
Popsicle is designed to be easiest way for making HTTP requests, offering a consistent and intuitive API that works on both node and the browser.
request('/users.json')
.then(function (res) {
console.log(res.body);
});
Installation
npm install popsicle --save
bower install popsicle --save
You will need a promise polyfill for older browsers and node <= 0.11.12
.
npm install es6-promise --save
bower install es6-promise --save
Apply the polyfill.
require('es6-promise').polyfill();
window.ES6Promise.polyfill();
Usage
var request = require('popsicle');
request({
method: 'POST',
url: 'http://example.com/api/users',
body: {
username: 'blakeembrey',
password: 'hunter2'
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(function (res) {
console.log(res.status);
console.log(res.body);
console.log(res.get('Content-Type'));
});
Handling Requests
- url The resource URI
- method The HTTP request method (default:
"GET"
) - headers An object of HTTP headers, header name to value (default:
{}
) - query An object or string to be appended to the URL
- body An object, string or form data to pass with the request
- timeout The number of milliseconds before cancelling the request (default:
Infinity
)
Automatically Serializing Body
Popsicle can automatically serialize the request body to a string. If an object is supplied, it'll automatically stringify as JSON unless the Content-Type
header was set otherwise. If the Content-Type
is multipart/form-data
or application/x-www-form-urlencoded
, it can also be automatically serialized.
request({
url: 'http://example.com/api/users',
body: {
username: 'blakeembrey',
profileImage: fs.createReadStream('image.png')
},
headers: {
'Content-Type': 'multipart/form-data'
}
});
Multipart Request Bodies
You can manually create a form data instance by calling popsicle.form
. When you pass a form data instance, it'll automatically set the correct Content-Type
too - complete with the boundary.
var form = request.form({
name: 'Blake Embrey',
image: '...'
});
request({
method: 'POST',
url: '/users',
body: form
});
Aborting Requests
All requests can be aborted during execution by calling Request#abort
. Requests won't normally start until chained anyway, but this will also abort the request before it starts.
var req = request('http://example.com');
setTimeout(function () {
req.abort();
}, 100);
req.catch(function (err) {
console.log(err);
});
Progress
The request object can also be used to check progress at any time.
Request#uploaded
can be used to check the upload progress (between 0
and 1
) of the current request. If the request is being streamed (node), the length may incorrectly return Infinity
to signify the number can't be calculated.
Request#downloaded
can be used to check the download progress (between 0
and 1
) of the current request instance. If the response did not respond with a Content-Length
header this can not be calculated properly and will return Infinity
.
Request#progress(fn)
can be used to register a progress event listener. It'll emit on upload and download progress events, which makes it useful for SPA progress bars. The function is called with an object ({ uploaded: 0, downloaded: 0, total: 0, aborted: false }
).
var req = request('http://example.com');
req.uploaded();
req.downloaded();
req.progress(function (e) {
console.log(e);
});
req.then(function (res) {
console.log(req.downloaded());
});
Handling Responses
Popsicle responses can be handled in multiple ways. Promises, node-style callbacks and streams (node only) are all supported.
Promises
Promises are the most expressive interface. Just chain using Request#then
or Request#catch
and continue.
request('/users')
.then(function (res) {
})
.catch(function (err) {
});
Callbacks
For tooling that expect node-style callbacks, you can use Request#exec
. This accepts a single function to call when the response is complete.
request('/users')
.exec(function (err, res) {
if (err) {
}
});
Streams (Node only)
Incomplete: Emits incorrect errors
On node, you can also chain using streams.
request('/users')
.pipe(fs.createWriteStream('users.json'));
Response Objects
Every Popsicle response will give a Response
object on success. The object provides an intuitive interface for requesting common properties.
- status An integer representing the HTTP response status code
- body An object (if parsable) or string that was the response HTTP body
- headers An object of lower-cased keys to header values
- statusType() Return an integer with the HTTP status type (E.g.
200 -> 2
) - info() Return a boolean indicating a HTTP status code between 100 and 199
- ok() Return a boolean indicating a HTTP status code between 200 and 299
- clientError() Return a boolean indicating a HTTP status code between 400 and 499
- serverError() Return a boolean indicating a HTTP status code between 500 and 599
- get(key) Retrieve a HTTP header using a case-insensitive key
- type() Return the response type (E.g.
application/json
)
Error Handling
All response handling methods can return an error. The errors can be categorized by checking properties on the error instance.
- parse error Response body failed to parse - invalid body or incorrect type (
err.parse
) - abort error The request was aborted by user intervention (
err.abort
) - timeout error The request timed out (
err.timeout
) - unavailable error Unable to connect to the remote URL (
err.unavailable
) - blocked error The request was blocked (HTTPS -> HTTP) (browsers,
err.blocked
) - csp error Request violates the documents Content Security Policy (browsers,
err.csp
)
Plugins
A simple plugin interface is exposed through Request#use
and promises.
Existing Plugins
- Status - Reject responses on HTTP failure status codes
- No Cache - Prevent caching of HTTP requests
- Basic Auth - Add basic authentication to requests
- Prefix - Automatically prefix all HTTP requests
Using Plugins
Plugins should expose a single function that accepts a Request
instance. For example:
function prefix (uri) {
return function (req) {
req.url = uri + req.url;
};
}
request('/user')
.use(prefix('http://example.com'))
.then(function (res) {
console.log(res.request.url);
});
Development and Testing
Install dependencies and run the test runners (node and browsers using Karma).
npm install && npm test
Related Projects
- Superagent - HTTP requests on node and browser
- Fetch - Browser polyfill for promise-based HTTP requests
- Axios - Similar API based on Angular's $http service
License
MIT