Popsicle is the easiest way to make HTTP requests - a consistent, intuitive and tiny API that works on node and the browser. 9.37 kB in browsers, after minification and gzipping, including dependencies (with
url
being the bulk of it).
popsicle.get('/users.json')
.then(function (res) {
console.log(res.status) //=> 200
console.log(res.body) //=> { ... }
console.log(res.headers) //=> { ... }
})
npm install popsicle --save
const popsicle = require('popsicle')
popsicle.request({
method: 'POST',
url: 'http://example.com/api/users',
body: {
username: 'blakeembrey',
password: 'hunter2'
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.use(popsicle.plugins.parse('json'))
.then(function (res) {
console.log(res.status) // => 200
console.log(res.body) //=> { ... }
console.log(res.get('Content-Type')) //=> 'application/json'
})
Popsicle is a promise-based HTTP request library designed for extensibility. Here's the functions you can import from popsicle
:
get
)defaults
Request
classResponse
class"GET"
).{}
).Infinity
)[stringify(), headers()]
)createTransport({ type: 'text' })
)stringify
(default)Automatically serialize the request body into a string (E.g. JSON, URL-encoded or multipart).
headers
(default)Sets up default headers for environments. For example, Content-Length
, User-Agent
, Accept
, etc.
parse
Automatically parses allowed response type(s).
popsicle.get('/users')
.use(popsicle.plugins.parse(['json', 'urlencoded']))
.then(() => ...)
Popsicle provides two transports, one for node (using {http,https}.request
) and one for browsers (using XMLHttpRequest
). These transports have a number of "types" built-in for handling the response body.
responseType === 'document'
(browsers)responseType === 'blob'
(browsers)responseType === 'arraybuffer'
(browsers)Uint8Array
(node.js)Node transport options
text
)true
)popsicle.jar()
) (default: null
)5
)2000000
)true
)307
and 308
status codes (default: () => false
)Buffer
or array of strings or Buffers
of trusted certificates in PEM formatnull
)null
)Browser transport options
text
)false
)Common methods have a short hand exported (created using defaults({ method })
).
popsicle.get('http://example.com/api/users')
popsicle.post('http://example.com/api/users')
popsicle.put('http://example.com/api/users')
popsicle.patch('http://example.com/api/users')
popsicle.del('http://example.com/api/users')
Create a new Popsicle instance with defaults pre-populated. Handy for a common cookie jar or transport to be used.
const cookiePopsicle = popsicle.defaults({
transport: popsicle.createTransport({
jar: popsicle.jar()
})
})
Popsicle will automatically serialize the request body using the stringify
plugin. If an object is supplied, it will automatically be stringified as JSON unless the Content-Type
was set otherwise. If the Content-Type
is application/json
, multipart/form-data
or application/x-www-form-urlencoded
, it will be automatically serialized accordingly.
popsicle.get({
url: 'http://example.com/api/users',
body: {
username: 'blakeembrey'
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
You can manually create a FormData
instance by calling popsicle.form
. When you pass a form data instance as the body, it'll automatically set the correct Content-Type
- complete with boundary.
const form = popsicle.form({
username: 'blakeembrey',
profileImage: fs.createReadStream('image.png')
})
form.append('x', 'y')
popsicle.post({
url: '/users',
body: form
})
You can create a reusable cookie jar instance for requests by calling popsicle.jar
.
const jar = popsicle.jar()
popsicle.request({
method: 'post',
url: '/users',
transport: popsicle.createTransport({
jar: jar
})
})
Calling any of the request functions will return an instance of Request
.
PopsicleError
instance.Request
from toOptions()
.abort
event.P.S. When cloning a request instance, the current middleware and events are copied. This allows event tricks like abort()
to also abort cloned request instances (e.g. in the case where working with request retries, and aborting should still work on re-attempts).
Promises are the most expressive interface. Just chain using Request#then
or Request#catch
and continue.
popsicle.get('/users')
.then(function (res) {
// Success!
})
.catch(function (err) {
// Something broke.
})
If you live on the edge, try with generators (co) or ES7 async
/await
.
co(function * () {
const users = yield popsicle.get('/users')
})
async function () {
const users = await popsicle.get('/users')
}
For tooling that expects node-style callbacks, you can use Request#exec
. This accepts a single function to call when the response is complete.
popsicle.get('/users')
.exec(function (err, res) {
if (err) {
// Something broke.
}
// Success!
})
All requests can be aborted before or during execution by calling Request#abort
.
const request = popsicle.get('http://example.com')
setTimeout(function () {
request.abort()
}, 100)
request.catch(function (err) {
console.log(err) //=> { message: 'Request aborted', code: 'EABORTED' }
})
The request object can be used to check progress at any time.
All percentage properties (request.uploaded
, request.downloaded
, request.completed
) are a number between 0
and 1
. Aborting the request will emit a progress event, if the request had started.
const request = popsicle.get('http://example.com')
request.uploaded //=> 0
request.downloaded //=> 0
request.on('progress', function () {
console.log(request) //=> { uploaded: 1, downloaded: 0, completed: 0.5, aborted: false }
})
request.then(function (response) {
console.log(request.downloaded) //=> 1
})
All response methods can return an error. Errors have a popsicle
property set to the request object and a code
string. The built-in codes are documented below, but custom errors can be created using request.error(message, code, cause)
.
Every response will give a Response
instance on success. T
200 -> 2
)application/json
)Plugins can be set as an array with the initial options (which overrides default plugins), or they can be used via Request#use
.
supertest
)throat
- Throttle promise-based functions with concurrency supportis-browser
- Check if your in a browser environment (E.g. Browserify, Webpack)parse-link-header
- Handy for parsing HTTP link headersPlugins must be a function that accept config and return a middleware function. For example, here's a basic URL prefix plugin.
function prefix (url) {
return function (self, next) {
self.url = url + self.url
return next()
}
}
popsicle.request('/user')
.use(prefix('http://example.com'))
.then(function (response) {
console.log(response.url) //=> "http://example.com/user"
})
Middleware functions accept two arguments - the current request and a function to proceed to the next middleware function (a la Koa 2.x
).
P.S. The middleware array is exposed on request.middleware
, which allows you to clone requests and tweak middleware - for example, using request.middleware.slice(request.middleware.indexOf(currentFn))
. This is useful, as the pre and post steps of previous middleware attach before currentFn
is executed.
Creating a custom transportation layer is just a matter creating an object with open
, abort
and use
options set. The open method should set any request information required between called as request._raw
. Abort must abort the current request instance, while open
must always resolve to a promise. You can set use
to an empty array if no plugins should be used by default. However, it's recommended you keep use
set to the defaults, or as close as possible using your transport layer.
This project is written using TypeScript and typings. Since version 1.3.1
, you can install the type definition using typings
.
typings install npm:popsicle --save
Note that for a brand new project you might need to add the definition for node via the following command:
typings install env~node --save --global
Make sure you add typings/index.d.ts
to your TypeScript project (using files
or includes
in tsconfig.json
) if it isn't already.
Install dependencies and run the test runners (node and Electron using Tape).
npm install && npm test
MIT