superagent = function (method, url) { // callback if ('function' == typeof url) { return new exports.Request('GET', method).end(url); } // url first if (1 == arguments.length) { return new exports.Request('GET', method); } return new exports.Request(method, url); }
n/a
function Request(method, url) { Stream.call(this); if ('string' != typeof url) url = format(url); this._agent = false; this._formData = null; this.method = method; this.url = url; _initHeaders(this); this.writable = true; this._redirects = 0; this.redirects(method === 'HEAD' ? 0 : 5); this.cookies = ''; this.qs = {}; this.qsRaw = []; this._redirectList = []; this._streamRequest = false; this.once('end', this.clearTimeout.bind(this)); }
...
/**
* Expose `request`.
*/
var request = exports = module.exports = function(method, url) {
// callback
if ('function' == typeof url) {
return new exports.Request('GET', method).end(url);
}
// url first
if (1 == arguments.length) {
return new exports.Request('GET', method);
}
...
function Response(req) { Stream.call(this); var res = this.res = req.res; this.request = req; this.req = req.req; this.text = res.text; this.body = res.body !== undefined ? res.body : {}; this.files = res.files || {}; this.buffered = 'string' == typeof this.text; this.header = this.headers = res.headers; this._setStatusProperties(res.statusCode); this._setHeaderProperties(this.header); this.setEncoding = res.setEncoding.bind(res); res.on('data', this.emit.bind(this, 'data')); res.on('end', this.emit.bind(this, 'end')); res.on('close', this.emit.bind(this, 'close')); res.on('error', this.emit.bind(this, 'error')); }
n/a
acl = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
function Agent(options) { if (!(this instanceof Agent)) return new Agent(options); if (options) { this._ca = options.ca; this._key = options.key; this._pfx = options.pfx; this._cert = options.cert; } this.jar = new CookieJar; }
n/a
checkout = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
client = function (method, url) { // callback if ('function' == typeof url) { return new exports.Request('GET', method).end(url); } // url first if (1 == arguments.length) { return new exports.Request('GET', method); } return new exports.Request(method, url); }
n/a
connect = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
copy = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
del = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
delete = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
get = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
...
```js
var nocache = require('superagent-no-cache');
var request = require('superagent');
var prefix = require('superagent-prefix')('/static');
request
.get('/some-url')
.query({ action: 'edit', city: 'London' }) // query string
.use(prefix) // Prefixes *only* this request
.use(nocache) // Prevents caching of *only* this request
.end(function(err, res){
// Do something
});
```
...
head = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
link = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
lock = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
m-search = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
merge = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
mkactivity = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
mkcalendar = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
mkcol = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
move = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
notify = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
options = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
patch = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
post = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
...
$ npm install superagent
```
Works with [browserify](https://github.com/substack/node-browserify) and should work with [webpack](https://github.com/visionmedia
/superagent/wiki/SuperAgent-for-Webpack)
```js
request
.post('/api/pet')
.send({ name: 'Manny', species: 'cat' })
.set('X-API-Key', 'foobar')
.set('Accept', 'application/json')
.end(function(err, res){
// Calling the end function will send the request
});
```
...
propfind = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
proppatch = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
purge = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
put = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
rebind = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
report = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
function RequestBase(obj) { if (obj) return mixin(obj); }
n/a
function ResponseBase(obj) { if (obj) return mixin(obj); }
n/a
search = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
subscribe = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
trace = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
unbind = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
unlink = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
unlock = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
unsubscribe = function (url, data, fn){ var req = request(method, url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); fn && req.end(fn); return req; }
n/a
function Request(method, url) { Stream.call(this); if ('string' != typeof url) url = format(url); this._agent = false; this._formData = null; this.method = method; this.url = url; _initHeaders(this); this.writable = true; this._redirects = 0; this.redirects(method === 'HEAD' ? 0 : 5); this.cookies = ''; this.qs = {}; this.qsRaw = []; this._redirectList = []; this._streamRequest = false; this.once('end', this.clearTimeout.bind(this)); }
...
/**
* Expose `request`.
*/
var request = exports = module.exports = function(method, url) {
// callback
if ('function' == typeof url) {
return new exports.Request('GET', method).end(url);
}
// url first
if (1 == arguments.length) {
return new exports.Request('GET', method);
}
...
function Stream() { EE.call(this); }
n/a
_appendQueryString = function (req){ var query = qs.stringify(this.qs, { indices: false, strictNullHandling: true }); query += ((query.length && this.qsRaw.length) ? '&' : '') + this.qsRaw.join('&'); req.path += query.length ? (~req.path.indexOf('?') ? '&' : '?') + query : ''; if (this._sort) { var index = req.path.indexOf('?'); if (index >= 0) { var queryArr = req.path.substring(index + 1).split('&'); if (isFunction(this._sort)) { queryArr.sort(this._sort); } else { queryArr.sort(); } req.path = req.path.substring(0, index) + '?' + queryArr.join('&'); } } }
...
}
this._endCalled = true;
// store callback
this._callback = fn || noop;
// querystring
this._appendQueryString();
return this._end();
};
Request.prototype._end = function() {
var self = this;
var xhr = this.xhr = request.getXHR();
...
_emitResponse = function (body, files){ var response = new Response(this); this.response = response; response.redirects = this._redirectList; if (undefined !== body) { response.body = body; } response.files = files; this.emit('response', response); return response; }
n/a
_end = function () { var self = this; var data = this._data; var req = this.req; var buffer = this._buffer; var method = this.method; this._setTimeouts(); // body if ('HEAD' != method && !req._headerSent) { // serialize stuff if ('string' != typeof data) { var contentType = req.getHeader('Content-Type') // Parse out just the content type from the header (ignore the charset) if (contentType) contentType = contentType.split(';')[0] var serialize = exports.serialize[contentType]; if (!serialize && isJSON(contentType)) { serialize = exports.serialize['application/json']; } if (serialize) data = serialize(data); } // content-length if (data && !req.getHeader('Content-Length')) { req.setHeader('Content-Length', Buffer.isBuffer(data) ? data.length : Buffer.byteLength(data)); } } // response req.once('response', function(res){ debug('%s %s -> %s', self.method, self.url, res.statusCode); if (self._responseTimeoutTimer) { clearTimeout(self._responseTimeoutTimer); } if (self.piped) { return; } var max = self._maxRedirects; var mime = utils.type(res.headers['content-type'] || '') || 'text/plain'; var type = mime.split('/')[0]; var multipart = 'multipart' == type; var redirect = isRedirect(res.statusCode); var parser = self._parser; var responseType = self._responseType; self.res = res; // redirect if (redirect && self._redirects++ != max) { return self._redirect(res); } if ('HEAD' == self.method) { self.emit('end'); self.callback(null, self._emitResponse()); return; } // zlib support if (self._shouldUnzip(res)) { unzip(req, res); } if (!parser) { if (responseType) { parser = exports.parse.image; // It's actually a generic Buffer buffer = true; } else if (multipart) { var form = new formidable.IncomingForm(); parser = form.parse.bind(form); buffer = true; } else if (isImageOrVideo(mime)) { parser = exports.parse.image; buffer = true; // For backwards-compatibility buffering default is ad-hoc MIME-dependent } else if (exports.parse[mime]) { parser = exports.parse[mime]; } else if ('text' == type) { parser = exports.parse.text; buffer = (buffer !== false); // everyone wants their own white-labeled json } else if (isJSON(mime)) { parser = exports.parse['application/json']; buffer = (buffer !== false); } else if (buffer) { parser = exports.parse.text; } } // by default only buffer text/*, json and messed up thing from hell if (undefined === buffer && isText(mime) || isJSON(mime)) { buffer = true; } var parserHandlesEnd = false; if (parser) { try { // Unbuffered parsers are supposed to emit response early, // which is weird BTW, because response.body won't be there. parserHandlesEnd = buffer; parser(res, function(err, obj, files) { if (self.timedout) { // Timeout has already handled all callbacks return; } // Intentional (non-timeout) abort is supposed to preserve partial response, // even if it doesn't parse. if (err && !self._aborted) { return self.callback(err); } if (parserHandlesEnd) { self.emit('end'); self.callback(null, self._emitResponse(obj, files)); } }); } catch (err) { self.callback(err); return; } } self.res = res; // unbuffered if (!buffer) { debug('unbuffered %s %s', self.method, self.url); self.callback(null, self._emitResponse()); if (multipart) return // allow multipart to handle end event res.once('end', function(){ debug('end %s %s', self.method, self.url); self.emit('end'); }) return; } // terminating eve ...
...
// store callback
this._callback = fn || noop;
// querystring
this._appendQueryString();
return this._end();
};
Request.prototype._end = function() {
var self = this;
var xhr = this.xhr = request.getXHR();
var data = this._formData || this._data;
...
_getFormData = function () { if (!this._formData) { this._formData = new FormData(); var that = this; this._formData.on('error', function(err) { that.emit('error', err); that.abort(); }); } return this._formData; }
...
Request.prototype.attach = function(field, file, options){
if (file) {
if (this._data) {
throw Error("superagent can't mix .send() and .attach()");
}
this._getFormData().append(field, file, options || file.name);
}
return this;
};
Request.prototype._getFormData = function(){
if (!this._formData) {
this._formData = new root.FormData();
...
function _isHost(obj) { return Buffer.isBuffer(obj) || obj instanceof Stream || obj instanceof FormData; }
...
return this.callback(err);
}
// CORS
if (this._withCredentials) xhr.withCredentials = true;
// body
if (!this._formData && 'GET' != this.method && 'HEAD' != this.method && '
string' != typeof data && !this._isHost(data)) {
// serialize stuff
var contentType = this._header['content-type'];
var serialize = this._serializer || request.serialize[contentType ? contentType.split(';')[0] : ''];
if (!serialize && isJSON(contentType)) {
serialize = request.serialize['application/json'];
}
if (serialize) data = serialize(data);
...
_isResponseOK = function (res) { if (!res) { return false; } if (this._okCallback) { return this._okCallback(res); } return res.status >= 200 && res.status < 300; }
...
return self.callback(err);
}
self.emit('response', res);
var new_err;
try {
if (!self._isResponseOK(res)) {
new_err = new Error(res.statusText || 'Unsuccessful HTTP response');
new_err.original = err;
new_err.response = res;
new_err.status = res.status;
}
} catch(e) {
new_err = e; // #985 touching res may cause INVALID_STATE_ERR on old Android
...
_pipeContinue = function (stream, options){ var self = this; this.req.once('response', function(res){ // redirect var redirect = isRedirect(res.statusCode); if (redirect && self._redirects++ != self._maxRedirects) { return self._redirect(res)._pipeContinue(stream, options); } self.res = res; self._emitResponse(); if (self._aborted) return; if (self._shouldUnzip(res)) { res.pipe(zlib.createUnzip()).pipe(stream, options); } else { res.pipe(stream, options); } res.once('end', function(){ self.emit('end'); }); }); return stream; }
n/a
_redirect = function (res){ var url = res.headers.location; if (!url) { return this.callback(new Error('No location header for redirect'), res); } debug('redirect %s -> %s', this.url, url); // location url = resolve(this.url, url); // ensure the response is being consumed // this is required for Node v0.10+ res.resume(); var headers = this.req._headers; var shouldStripCookie = parse(url).host !== parse(this.url).host; // implementation of 302 following defacto standard if (res.statusCode == 301 || res.statusCode == 302){ // strip Content-* related fields // in case of POST etc headers = utils.cleanHeader(this.req._headers, shouldStripCookie); // force GET this.method = 'HEAD' == this.method ? 'HEAD' : 'GET'; // clear data this._data = null; } // 303 is always GET if (res.statusCode == 303) { // strip Content-* related fields // in case of POST etc headers = utils.cleanHeader(this.req._headers, shouldStripCookie); // force method this.method = 'GET'; // clear data this._data = null; } // 307 preserves method // 308 preserves method delete headers.host; delete this.req; delete this._formData; // remove all add header except User-Agent _initHeaders(this) // redirect this._endCalled = false; this.url = url; this.qs = {}; this.qsRaw = []; this.set(headers); this.emit('redirect', res); this._redirectList.push(this.url); this.end(this._callback); return this; }
n/a
_retry = function () { this.clearTimeout(); // node if (this.req) { this.req = null; this.req = this.request(); } this._aborted = false; this.timedout = false; return this._end(); }
...
* @param {Response} res
* @api private
*/
Request.prototype.callback = function(err, res){
// console.log(this._retries, this._maxRetries)
if (this._maxRetries && this._retries++ < this._maxRetries && shouldRetry(err, res)) {
return this._retry();
}
var fn = this._callback;
this.clearTimeout();
if (err) {
if (this._maxRetries) err.retries = this._retries - 1;
...
_setTimeouts = function () { var self = this; // deadline if (this._timeout && !this._timer) { this._timer = setTimeout(function(){ self._timeoutError('Timeout of ', self._timeout, 'ETIME'); }, this._timeout); } // response timeout if (this._responseTimeout && !this._responseTimeoutTimer) { this._responseTimeoutTimer = setTimeout(function(){ self._timeoutError('Response timeout of ', self._responseTimeout, 'ETIMEDOUT'); }, this._responseTimeout); } }
...
};
Request.prototype._end = function() {
var self = this;
var xhr = this.xhr = request.getXHR();
var data = this._formData || this._data;
this._setTimeouts();
// state change
xhr.onreadystatechange = function(){
var readyState = xhr.readyState;
if (readyState >= 2 && self._responseTimeoutTimer) {
clearTimeout(self._responseTimeoutTimer);
}
...
_shouldUnzip = function (res){ if (res.statusCode === 204 || res.statusCode === 304) { // These aren't supposed to have any body return false; } // header content is a string, and distinction between 0 and no information is crucial if ('0' === res.headers['content-length']) { // We know that the body is empty (unfortunately, this check does not cover chunked encoding) return false; } // console.log(res); return /^\s*(?:deflate|gzip)\s*$/.test(res.headers['content-encoding']); }
n/a
_timeoutError = function (reason, timeout, errno){ if (this._aborted) { return; } var err = new Error(reason + timeout + 'ms exceeded'); err.timeout = timeout; err.code = 'ECONNABORTED'; err.errno = errno; this.timedout = true; this.abort(); this.callback(err); }
...
RequestBase.prototype._setTimeouts = function() {
var self = this;
// deadline
if (this._timeout && !this._timer) {
this._timer = setTimeout(function(){
self._timeoutError('Timeout of ', self._timeout, 'ETIME');
}, this._timeout);
}
// response timeout
if (this._responseTimeout && !this._responseTimeoutTimer) {
this._responseTimeoutTimer = setTimeout(function(){
self._timeoutError('Response timeout of ', self._responseTimeout, 'ETIMEDOUT');
}, this._responseTimeout);
...
abort = function (){ if (this._aborted) { return this; } this._aborted = true; this.xhr && this.xhr.abort(); // browser this.req && this.req.abort(); // node this.clearTimeout(); this.emit('abort'); return this; }
...
* @api public
*/
RequestBase.prototype.abort = function(){
if (this._aborted) {
return this;
}
this._aborted = true;
this.xhr && this.xhr.abort(); // browser
this.req && this.req.abort(); // node
this.clearTimeout();
this.emit('abort');
return this;
};
/**
...
accept = function (type){ return this.set('Accept', ~type.indexOf('/') ? type : mime.lookup(type)); }
...
* Set Accept to `type`, mapping values from `request.types`.
*
* Examples:
*
* superagent.types.json = 'application/json';
*
* request.get('/agent')
* .accept('json')
* .end(callback);
*
* request.get('/agent')
* .accept('application/json')
* .end(callback);
*
* @param {String} accept
...
agent = function (agent){ if (!arguments.length) return this._agent; this._agent = agent; return this; }
n/a
attach = function (field, file, options){ if (file) { if (this._data) { throw Error("superagent can't mix .send() and .attach()"); } var o = options || {}; if ('string' == typeof options) { o = { filename: options }; } if ('string' == typeof file) { if (!o.filename) o.filename = file; debug('creating `fs.ReadStream` instance for file: %s', file); file = fs.createReadStream(file); } else if (!o.filename && file.path) { o.filename = file.path; } this._getFormData().append(field, file, o); } return this; }
...
/**
* Queue the given `file` as an attachment to the specified `field`,
* with optional `options` (or filename).
*
* ``` js
* request.post('/upload')
* .attach('content', new Blob(['<a id="a"><
b id="b">hey!</b></a>'], { type: "text/html"}))
* .end(callback);
* ```
*
* @param {String} field
* @param {Blob|File} file
* @param {String|Object} options
* @return {Request} for chaining
...
auth = function (user, pass, options){ if (1 === arguments.length) pass = ''; if (2 === arguments.length && typeof pass === 'object') options = pass; if (!options) { options = { type: 'basic' }; } switch (options.type) { case 'bearer': return this.set('Authorization', 'Bearer ' + user); default: // 'basic' if (!~user.indexOf(':')) user = user + ':'; var str = new Buffer(user + pass).toString('base64'); return this.set('Authorization', 'Basic ' + str); } }
...
break;
case 'auto':
this.username = user;
this.password = pass;
break;
case 'bearer': // usage would be .auth(accessToken, { type: 'bearer
' })
this.set('Authorization', 'Bearer ' + user);
break;
}
return this;
};
/**
...
buffer = function (val){ this._buffer = (false !== val); return this; }
n/a
ca = function (cert){ this._ca = cert; return this; }
n/a
callback = function (err, res){ // console.log(this._retries, this._maxRetries) if (this._maxRetries && this._retries++ < this._maxRetries && shouldRetry(err, res)) { return this._retry(); } // Avoid the error which is emitted from 'socket hang up' to cause the fn undefined error on JS runtime. var fn = this._callback || noop; this.clearTimeout(); if (this.called) return console.warn('superagent: double callback bug'); this.called = true; if (!err) { if (this._isResponseOK(res)) { return fn(err, res); } var msg = 'Unsuccessful HTTP response'; if (res) { msg = http.STATUS_CODES[res.status] || msg; } err = new Error(msg); err.status = res ? res.status : undefined; } err.response = res; if (this._maxRetries) err.retries = this._retries - 1; // only emit error event if there is a listener // otherwise we assume the callback to `.end()` will get the error if (err && this.listeners('error').length > 0) { this.emit('error', err); } fn(err, res); }
...
err.status = self.xhr.status ? self.xhr.status : null;
err.statusCode = err.status; // backwards-compat only
} else {
err.rawResponse = null;
err.status = null;
}
return self.callback(err);
}
self.emit('response', res);
var new_err;
try {
if (!self._isResponseOK(res)) {
...
catch = function (cb) { return this.then(undefined, cb); }
n/a
cert = function (cert){ this._cert = cert; return this; }
n/a
function _clearTimeout(){ clearTimeout(this._timer); clearTimeout(this._responseTimeoutTimer); delete this._timer; delete this._responseTimeoutTimer; return this; }
...
Request.prototype.callback = function(err, res){
// console.log(this._retries, this._maxRetries)
if (this._maxRetries && this._retries++ < this._maxRetries && shouldRetry(err, res)) {
return this._retry();
}
var fn = this._callback;
this.clearTimeout();
if (err) {
if (this._maxRetries) err.retries = this._retries - 1;
this.emit('error', err);
}
fn(err, res);
...
end = function (fn){ this.request(); debug('%s %s', this.method, this.url); if (this._endCalled) { console.warn("Warning: .end() was called twice. This is not supported in superagent"); } this._endCalled = true; // store callback this._callback = fn || noop; return this._end(); }
...
```js
request
.post('/api/pet')
.send({ name: 'Manny', species: 'cat' })
.set('X-API-Key', 'foobar')
.set('Accept', 'application/json')
.end(function(err, res){
// Calling the end function will send the request
});
```
## Supported browsers and Node versions
Tested browsers:
...
field = function (name, val) { // name should be either a string or an object. if (null === name || undefined === name) { throw new Error('.field(name, val) name can not be empty'); } if (this._data) { console.error(".field() can't be used if .send() is used. Please use only .send() or only .field() & .attach()"); } if (isObject(name)) { for (var key in name) { this.field(key, name[key]); } return this; } if (Array.isArray(val)) { for (var i in val) { this.field(name, val[i]); } return this; } // val should be defined now if (null === val || undefined === val) { throw new Error('.field(name, val) val can not be empty'); } if ('boolean' === typeof val) { val = '' + val; } this._getFormData().append(name, val); return this; }
...
Tested browsers:
- Latest Firefox, Chrome, Safari
- Latest Android, iPhone
- IE10 through latest. IE9 with polyfills.
Even though IE9 is supported, a polyfill for `window.FormData` is required for `.field()`.
Node 4 or later is required.
# Plugins
SuperAgent is easily extended via plugins.
...
get = function (field){ return this._header[field.toLowerCase()]; }
...
```js
var nocache = require('superagent-no-cache');
var request = require('superagent');
var prefix = require('superagent-prefix')('/static');
request
.get('/some-url')
.query({ action: 'edit', city: 'London' }) // query string
.use(prefix) // Prefixes *only* this request
.use(nocache) // Prevents caching of *only* this request
.end(function(err, res){
// Do something
});
```
...
getHeader = function (field){ return this._header[field.toLowerCase()]; }
n/a
key = function (cert){ this._key = cert; return this; }
n/a
ok = function (cb) { if ('function' !== typeof cb) throw Error("Callback required"); this._okCallback = cb; return this; }
n/a
function parse(fn){ this._parser = fn; return this; }
n/a
pfx = function (cert){ this._pfx = cert; return this; }
n/a
pipe = function (stream, options){ this.piped = true; // HACK... this.buffer(false); this.end(); return this._pipeContinue(stream, options); }
n/a
query = function (val){ if ('string' == typeof val) { this.qsRaw.push(val); return this; } extend(this.qs, val); return this; }
...
```js
var nocache = require('superagent-no-cache');
var request = require('superagent');
var prefix = require('superagent-prefix')('/static');
request
.get('/some-url')
.query({ action: 'edit', city: 'London' }) // query string
.use(prefix) // Prefixes *only* this request
.use(nocache) // Prevents caching of *only* this request
.end(function(err, res){
// Do something
});
```
...
redirects = function (n){ this._maxRedirects = n; return this; }
n/a
request = function (){ if (this.req) return this.req; var self = this; var options = {}; var url = this.url; var retries = this._retries; // default to http:// if (0 != url.indexOf('http')) url = 'http://' + url; url = parse(url); // support unix sockets if (/^https?\+unix:/.test(url.protocol) === true) { // get the protocol url.protocol = url.protocol.split('+')[0] + ':'; // get the socket, path var unixParts = url.path.match(/^([^/]+)(.+)$/); options.socketPath = unixParts[1].replace(/%2F/g, '/'); url.pathname = unixParts[2]; } // options options.method = this.method; options.port = url.port; options.path = url.pathname; options.host = url.hostname; options.ca = this._ca; options.key = this._key; options.pfx = this._pfx; options.cert = this._cert; options.agent = this._agent; // initiate request var mod = exports.protocols[url.protocol]; // request var req = this.req = mod.request(options); if ('HEAD' != options.method) { req.setHeader('Accept-Encoding', 'gzip, deflate'); } this.protocol = url.protocol; this.host = url.host; // expose events req.once('drain', function(){ self.emit('drain'); }); req.once('error', function(err){ // flag abortion here for out timeouts // because node will emit a faux-error "socket hang up" // when request is aborted before a connection is made if (self._aborted) return; // if not the same, we are in the **old** (cancelled) request, // so need to continue (same as for above) if (self._retries !== retries) return; // if we've received a response then we don't want to let // an error in the request blow up the response if (self.response) return; self.callback(err); }); // auth if (url.auth) { var auth = url.auth.split(':'); this.auth(auth[0], auth[1]); } // query if (url.search) this.query(url.search.substr(1)); // add cookies if (this.cookies) req.setHeader('Cookie', this.cookies); for (var key in this.header) { if (this.header.hasOwnProperty(key)) req.setHeader(key, this.header[key]); } try { this._appendQueryString(req); } catch (e) { return this.emit('error', e); } return req; }
...
RequestBase.prototype._retry = function() {
this.clearTimeout();
// node
if (this.req) {
this.req = null;
this.req = this.request();
}
this._aborted = false;
this.timedout = false;
return this._end();
};
...
responseType = function (val){ this._responseType = val; return this; }
...
* which return Blob and ArrayBuffer, respectively.
*
* In Node all values result in Buffer.
*
* Examples:
*
* req.get('/')
* .responseType('blob')
* .end(callback);
*
* @param {String} val
* @return {Request} for chaining
* @api public
*/
...
function retry(count){ // Default to 1 if no count passed or true if (arguments.length === 0 || count === true) count = 1; if (count <= 0) count = 0; this._maxRetries = count; this._retries = 0; return this; }
n/a
send = function (data){ var isObj = isObject(data); var type = this._header['content-type']; if (this._formData) { console.error(".send() can't be used if .attach() or .field() is used. Please use only .send() or only .field() & .attach()"); } if (isObj && !this._data) { if (Array.isArray(data)) { this._data = []; } else if (!this._isHost(data)) { this._data = {}; } } else if (data && this._data && this._isHost(this._data)) { throw Error("Can't merge these send calls"); } // merge if (isObj && isObject(this._data)) { for (var key in data) { this._data[key] = data[key]; } } else if ('string' == typeof data) { // default to x-www-form-urlencoded if (!type) this.type('form'); type = this._header['content-type']; if ('application/x-www-form-urlencoded' == type) { this._data = this._data ? this._data + '&' + data : data; } else { this._data = (this._data || '') + data; } } else { this._data = data; } if (!isObj || this._isHost(data)) { return this; } // default to json if (!type) this.type('json'); return this; }
...
```
Works with [browserify](https://github.com/substack/node-browserify) and should work with [webpack](https://github.com/visionmedia
/superagent/wiki/SuperAgent-for-Webpack)
```js
request
.post('/api/pet')
.send({ name: 'Manny', species: 'cat' })
.set('X-API-Key', 'foobar')
.set('Accept', 'application/json')
.end(function(err, res){
// Calling the end function will send the request
});
```
...
function serialize(fn){ this._serializer = fn; return this; }
n/a
set = function (field, val){ if (isObject(field)) { for (var key in field) { this.set(key, field[key]); } return this; } this._header[field.toLowerCase()] = val; this.header[field] = val; return this; }
...
Works with [browserify](https://github.com/substack/node-browserify) and should work with [webpack](https://github.com/visionmedia
/superagent/wiki/SuperAgent-for-Webpack)
```js
request
.post('/api/pet')
.send({ name: 'Manny', species: 'cat' })
.set('X-API-Key', 'foobar')
.set('Accept', 'application/json')
.end(function(err, res){
// Calling the end function will send the request
});
```
## Supported browsers and Node versions
...
sortQuery = function (sort) { // _sort default to true but otherwise can be a function or boolean this._sort = typeof sort === 'undefined' ? true : sort; return this; }
...
*
* Examples:
*
* // default order
* request.get('/user')
* .query('name=Nick')
* .query('search=Manny')
* .sortQuery()
* .end(callback)
*
* // customized sort function
* request.get('/user')
* .query('name=Nick')
* .query('search=Manny')
* .sortQuery(function(a, b){
...
function then(resolve, reject) { if (!this._fullfilledPromise) { var self = this; if (this._endCalled) { console.warn("Warning: superagent request was sent twice, because both .end() and .then() were called. Never call .end() if you use promises"); } this._fullfilledPromise = new Promise(function(innerResolve, innerReject){ self.end(function(err, res){ if (err) innerReject(err); else innerResolve(res); }); }); } return this._fullfilledPromise.then(resolve, reject); }
...
* @return {Request}
*/
RequestBase.prototype.then = function then(resolve, reject) {
if (!this._fullfilledPromise) {
var self = this;
if (this._endCalled) {
console.warn("Warning: superagent request was sent twice, because both .end() and .
then() were called. Never call .end() if you use promises");
}
this._fullfilledPromise = new Promise(function(innerResolve, innerReject){
self.end(function(err, res){
if (err) innerReject(err); else innerResolve(res);
});
});
}
...
function timeout(options){ if (!options || 'object' !== typeof options) { this._timeout = options; this._responseTimeout = 0; return this; } for(var option in options) { switch(option) { case 'deadline': this._timeout = options.deadline; break; case 'response': this._responseTimeout = options.response; break; default: console.warn("Unknown timeout option", option); } } return this; }
n/a
toJSON = function (){ return { method: this.method, url: this.url, data: this._data, headers: this._header }; }
n/a
type = function (type){ return this.set('Content-Type', ~type.indexOf('/') ? type : mime.lookup(type)); }
...
* Set Content-Type to `type`, mapping values from `request.types`.
*
* Examples:
*
* superagent.types.xml = 'application/xml';
*
* request.post('/')
* .type('xml')
* .send(xmlstring)
* .end(callback);
*
* request.post('/')
* .type('application/xml')
* .send(xmlstring)
* .end(callback);
...
unset = function (field){ delete this._header[field.toLowerCase()]; delete this.header[field]; return this; }
...
/**
* Remove header `field`.
* Case-insensitive.
*
* Example:
*
* req.get('/')
* .unset('User-Agent')
* .end(callback);
*
* @param {String} field
*/
RequestBase.prototype.unset = function(field){
delete this._header[field.toLowerCase()];
delete this.header[field];
...
function use(fn) { fn(this); return this; }
...
var nocache = require('superagent-no-cache');
var request = require('superagent');
var prefix = require('superagent-prefix')('/static');
request
.get('/some-url')
.query({ action: 'edit', city: 'London' }) // query string
.use(prefix) // Prefixes *only* this request
.use(nocache) // Prevents caching of *only* this request
.end(function(err, res){
// Do something
});
```
Existing plugins:
...
withCredentials = function (on){ // This is browser-only functionality. Node side is no-op. if(on==undefined) on = true; this._withCredentials = on; return this; }
n/a
write = function (data, encoding){ var req = this.request(); if (!this._streamRequest) { this._streamRequest = true; } return req.write(data, encoding); }
n/a
function Response(req) { Stream.call(this); var res = this.res = req.res; this.request = req; this.req = req.req; this.text = res.text; this.body = res.body !== undefined ? res.body : {}; this.files = res.files || {}; this.buffered = 'string' == typeof this.text; this.header = this.headers = res.headers; this._setStatusProperties(res.statusCode); this._setHeaderProperties(this.header); this.setEncoding = res.setEncoding.bind(res); res.on('data', this.emit.bind(this, 'data')); res.on('end', this.emit.bind(this, 'end')); res.on('close', this.emit.bind(this, 'close')); res.on('error', this.emit.bind(this, 'error')); }
n/a
function Stream() { EE.call(this); }
n/a
_setHeaderProperties = function (header){ // TODO: moar! // TODO: make this a util // content-type var ct = header['content-type'] || ''; this.type = utils.type(ct); // params var params = utils.params(ct); for (var key in params) this[key] = params[key]; this.links = {}; // links try { if (header.link) { this.links = utils.parseLinks(header.link); } } catch (err) { // ignore } }
...
}
this._setStatusProperties(status);
this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders());
// getAllResponseHeaders sometimes falsely returns "" for CORS requests, but
// getResponseHeader still works. so we get content-type even if getting
// other headers fails.
this.header['content-type'] = this.xhr.getResponseHeader('content-type');
this._setHeaderProperties(this.header);
if (null === this.text && req._responseType) {
this.body = this.xhr.response;
} else {
this.body = this.req.method != 'HEAD'
? this._parseBody(this.text ? this.text : this.xhr.response)
: null;
...
_setStatusProperties = function (status){ var type = status / 100 | 0; // status / class this.status = this.statusCode = status; this.statusType = type; // basics this.info = 1 == type; this.ok = 2 == type; this.redirect = 3 == type; this.clientError = 4 == type; this.serverError = 5 == type; this.error = (4 == type || 5 == type) ? this.toError() : false; // sugar this.accepted = 202 == status; this.noContent = 204 == status; this.badRequest = 400 == status; this.unauthorized = 401 == status; this.notAcceptable = 406 == status; this.forbidden = 403 == status; this.notFound = 404 == status; }
...
: null;
this.statusText = this.req.xhr.statusText;
var status = this.xhr.status;
// handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request
if (status === 1223) {
status = 204;
}
this._setStatusProperties(status);
this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders());
// getAllResponseHeaders sometimes falsely returns "" for CORS requests, but
// getResponseHeader still works. so we get content-type even if getting
// other headers fails.
this.header['content-type'] = this.xhr.getResponseHeader('content-type');
this._setHeaderProperties(this.header);
...
destroy = function (err){ this.res.destroy(err); }
n/a
get = function (field){ return this.header[field.toLowerCase()]; }
...
```js
var nocache = require('superagent-no-cache');
var request = require('superagent');
var prefix = require('superagent-prefix')('/static');
request
.get('/some-url')
.query({ action: 'edit', city: 'London' }) // query string
.use(prefix) // Prefixes *only* this request
.use(nocache) // Prevents caching of *only* this request
.end(function(err, res){
// Do something
});
```
...
pause = function (){ this.res.pause(); }
n/a
resume = function (){ this.res.resume(); }
n/a
setStatusProperties = function (status){ console.warn("In superagent 2.x setStatusProperties is a private method"); return this._setStatusProperties(status); }
n/a
toError = function (){ var req = this.req; var method = req.method; var path = req.path; var msg = 'cannot ' + method + ' ' + path + ' (' + this.status + ')'; var err = new Error(msg); err.status = this.status; err.text = this.text; err.method = method; err.path = path; return err; }
...
// basics
this.info = 1 == type;
this.ok = 2 == type;
this.redirect = 3 == type;
this.clientError = 4 == type;
this.serverError = 5 == type;
this.error = (4 == type || 5 == type)
? this.toError()
: false;
// sugar
this.accepted = 202 == status;
this.noContent = 204 == status;
this.badRequest = 400 == status;
this.unauthorized = 401 == status;
...
toJSON = function (){ return { req: this.request.toJSON(), header: this.header, status: this.status, text: this.text }; }
n/a
function Agent(options) { if (!(this instanceof Agent)) return new Agent(options); if (options) { this._ca = options.ca; this._key = options.key; this._pfx = options.pfx; this._cert = options.cert; } this.jar = new CookieJar; }
n/a
_attachCookies = function (req){ var url = parse(req.url); var access = CookieAccess(url.hostname, url.pathname, 'https:' == url.protocol); var cookies = this.jar.getCookies(access).toValueString(); req.cookies = cookies; }
n/a
_saveCookies = function (res){ var cookies = res.headers['set-cookie']; if (cookies) this.jar.setCookies(cookies); }
n/a
acl = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
bind = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
...
e.percent = e.loaded / e.total * 100;
}
e.direction = direction;
self.emit('progress', e);
}
if (this.hasListeners('progress')) {
try {
xhr.onprogress = handleProgress.bind(null, 'download');
if (xhr.upload) {
xhr.upload.onprogress = handleProgress.bind(null, 'upload');
}
} catch(e) {
// Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist.
// Reported here:
// https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web
-worker-context
...
checkout = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
connect = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
copy = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
del = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
delete = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
get = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
...
```js
var nocache = require('superagent-no-cache');
var request = require('superagent');
var prefix = require('superagent-prefix')('/static');
request
.get('/some-url')
.query({ action: 'edit', city: 'London' }) // query string
.use(prefix) // Prefixes *only* this request
.use(nocache) // Prevents caching of *only* this request
.end(function(err, res){
// Do something
});
```
...
head = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
link = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
lock = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
m-search = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
merge = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
mkactivity = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
mkcalendar = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
mkcol = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
move = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
notify = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
options = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
patch = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
post = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
...
$ npm install superagent
```
Works with [browserify](https://github.com/substack/node-browserify) and should work with [webpack](https://github.com/visionmedia
/superagent/wiki/SuperAgent-for-Webpack)
```js
request
.post('/api/pet')
.send({ name: 'Manny', species: 'cat' })
.set('X-API-Key', 'foobar')
.set('Accept', 'application/json')
.end(function(err, res){
// Calling the end function will send the request
});
```
...
propfind = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
proppatch = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
purge = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
put = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
rebind = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
report = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
search = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
subscribe = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
trace = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
unbind = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
unlink = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
unlock = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
unsubscribe = function (url, fn){ var req = new request.Request(method, url); req.ca(this._ca); req.key(this._key); req.pfx(this._pfx); req.cert(this._cert); req.on('response', this._saveCookies.bind(this)); req.on('redirect', this._saveCookies.bind(this)); req.on('redirect', this._attachCookies.bind(this, req)); this._attachCookies(req); fn && req.end(fn); return req; }
n/a
client = function (method, url) { // callback if ('function' == typeof url) { return new exports.Request('GET', method).end(url); } // url first if (1 == arguments.length) { return new exports.Request('GET', method); } return new exports.Request(method, url); }
n/a
function Request(method, url) { var self = this; this._query = this._query || []; this.method = method; this.url = url; this.header = {}; // preserves header name case this._header = {}; // coerces header names to lowercase this.on('end', function(){ var err = null; var res = null; try { res = new Response(self); } catch(e) { err = new Error('Parser is unable to parse the response'); err.parse = true; err.original = e; // issue #675: return the raw response if the response parsing fails if (self.xhr) { // ie9 doesn't have 'response' property err.rawResponse = typeof self.xhr.responseType == 'undefined' ? self.xhr.responseText : self.xhr.response; // issue #876: return the http status code if the response parsing fails err.status = self.xhr.status ? self.xhr.status : null; err.statusCode = err.status; // backwards-compat only } else { err.rawResponse = null; err.status = null; } return self.callback(err); } self.emit('response', res); var new_err; try { if (!self._isResponseOK(res)) { new_err = new Error(res.statusText || 'Unsuccessful HTTP response'); new_err.original = err; new_err.response = res; new_err.status = res.status; } } catch(e) { new_err = e; // #985 touching res may cause INVALID_STATE_ERR on old Android } // #1000 don't catch errors from the callback to avoid double calling it if (new_err) { self.callback(new_err, res); } else { self.callback(null, res); } }); }
...
/**
* Expose `request`.
*/
var request = exports = module.exports = function(method, url) {
// callback
if ('function' == typeof url) {
return new exports.Request('GET', method).end(url);
}
// url first
if (1 == arguments.length) {
return new exports.Request('GET', method);
}
...
function Response(req) { this.req = req; this.xhr = this.req.xhr; // responseText is accessible only if responseType is '' or 'text' and on older browsers this.text = ((this.req.method !='HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text')) || typeof this.xhr .responseType === 'undefined') ? this.xhr.responseText : null; this.statusText = this.req.xhr.statusText; var status = this.xhr.status; // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request if (status === 1223) { status = 204; } this._setStatusProperties(status); this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders()); // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but // getResponseHeader still works. so we get content-type even if getting // other headers fails. this.header['content-type'] = this.xhr.getResponseHeader('content-type'); this._setHeaderProperties(this.header); if (null === this.text && req._responseType) { this.body = this.xhr.response; } else { this.body = this.req.method != 'HEAD' ? this._parseBody(this.text ? this.text : this.xhr.response) : null; } }
n/a
function del(url, data, fn){ var req = request('DELETE', url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); if (fn) req.end(fn); return req; }
n/a
function del(url, data, fn){ var req = request('DELETE', url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); if (fn) req.end(fn); return req; }
n/a
get = function (url, data, fn){ var req = request('GET', url); if ('function' == typeof data) fn = data, data = null; if (data) req.query(data); if (fn) req.end(fn); return req; }
...
```js
var nocache = require('superagent-no-cache');
var request = require('superagent');
var prefix = require('superagent-prefix')('/static');
request
.get('/some-url')
.query({ action: 'edit', city: 'London' }) // query string
.use(prefix) // Prefixes *only* this request
.use(nocache) // Prevents caching of *only* this request
.end(function(err, res){
// Do something
});
```
...
getXHR = function () { if (root.XMLHttpRequest && (!root.location || 'file:' != root.location.protocol || !root.ActiveXObject)) { return new XMLHttpRequest; } else { try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {} try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {} try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {} try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {} } throw Error("Browser-only verison of superagent could not find XHR"); }
...
this._appendQueryString();
return this._end();
};
Request.prototype._end = function() {
var self = this;
var xhr = this.xhr = request.getXHR();
var data = this._formData || this._data;
this._setTimeouts();
// state change
xhr.onreadystatechange = function(){
var readyState = xhr.readyState;
...
head = function (url, data, fn){ var req = request('HEAD', url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); if (fn) req.end(fn); return req; }
n/a
options = function (url, data, fn){ var req = request('OPTIONS', url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); if (fn) req.end(fn); return req; }
n/a
function parseString(str) { var obj = {}; var pairs = str.split('&'); var pair; var pos; for (var i = 0, len = pairs.length; i < len; ++i) { pair = pairs[i]; pos = pair.indexOf('='); if (pos == -1) { obj[decodeURIComponent(pair)] = ''; } else { obj[decodeURIComponent(pair.slice(0, pos))] = decodeURIComponent(pair.slice(pos + 1)); } } return obj; }
n/a
patch = function (url, data, fn){ var req = request('PATCH', url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); if (fn) req.end(fn); return req; }
n/a
post = function (url, data, fn){ var req = request('POST', url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); if (fn) req.end(fn); return req; }
...
$ npm install superagent
```
Works with [browserify](https://github.com/substack/node-browserify) and should work with [webpack](https://github.com/visionmedia
/superagent/wiki/SuperAgent-for-Webpack)
```js
request
.post('/api/pet')
.send({ name: 'Manny', species: 'cat' })
.set('X-API-Key', 'foobar')
.set('Accept', 'application/json')
.end(function(err, res){
// Calling the end function will send the request
});
```
...
put = function (url, data, fn){ var req = request('PUT', url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); if (fn) req.end(fn); return req; }
n/a
function serialize(obj) { if (!isObject(obj)) return obj; var pairs = []; for (var key in obj) { pushEncodedKeyValuePair(pairs, key, obj[key]); } return pairs.join('&'); }
n/a
image = function (res, fn){ var data = []; // Binary data needs binary storage res.on('data', function(chunk){ data.push(chunk); }); res.on('end', function () { fn(null, Buffer.concat(data)); }); }
n/a
text = function (res, fn){ res.text = ''; res.setEncoding('utf8'); res.on('data', function(chunk){ res.text += chunk; }); res.on('end', fn); }
n/a
function RequestBase(obj) { if (obj) return mixin(obj); }
n/a
_isResponseOK = function (res) { if (!res) { return false; } if (this._okCallback) { return this._okCallback(res); } return res.status >= 200 && res.status < 300; }
...
return self.callback(err);
}
self.emit('response', res);
var new_err;
try {
if (!self._isResponseOK(res)) {
new_err = new Error(res.statusText || 'Unsuccessful HTTP response');
new_err.original = err;
new_err.response = res;
new_err.status = res.status;
}
} catch(e) {
new_err = e; // #985 touching res may cause INVALID_STATE_ERR on old Android
...
_retry = function () { this.clearTimeout(); // node if (this.req) { this.req = null; this.req = this.request(); } this._aborted = false; this.timedout = false; return this._end(); }
...
* @param {Response} res
* @api private
*/
Request.prototype.callback = function(err, res){
// console.log(this._retries, this._maxRetries)
if (this._maxRetries && this._retries++ < this._maxRetries && shouldRetry(err, res)) {
return this._retry();
}
var fn = this._callback;
this.clearTimeout();
if (err) {
if (this._maxRetries) err.retries = this._retries - 1;
...
_setTimeouts = function () { var self = this; // deadline if (this._timeout && !this._timer) { this._timer = setTimeout(function(){ self._timeoutError('Timeout of ', self._timeout, 'ETIME'); }, this._timeout); } // response timeout if (this._responseTimeout && !this._responseTimeoutTimer) { this._responseTimeoutTimer = setTimeout(function(){ self._timeoutError('Response timeout of ', self._responseTimeout, 'ETIMEDOUT'); }, this._responseTimeout); } }
...
};
Request.prototype._end = function() {
var self = this;
var xhr = this.xhr = request.getXHR();
var data = this._formData || this._data;
this._setTimeouts();
// state change
xhr.onreadystatechange = function(){
var readyState = xhr.readyState;
if (readyState >= 2 && self._responseTimeoutTimer) {
clearTimeout(self._responseTimeoutTimer);
}
...
_timeoutError = function (reason, timeout, errno){ if (this._aborted) { return; } var err = new Error(reason + timeout + 'ms exceeded'); err.timeout = timeout; err.code = 'ECONNABORTED'; err.errno = errno; this.timedout = true; this.abort(); this.callback(err); }
...
RequestBase.prototype._setTimeouts = function() {
var self = this;
// deadline
if (this._timeout && !this._timer) {
this._timer = setTimeout(function(){
self._timeoutError('Timeout of ', self._timeout, 'ETIME');
}, this._timeout);
}
// response timeout
if (this._responseTimeout && !this._responseTimeoutTimer) {
this._responseTimeoutTimer = setTimeout(function(){
self._timeoutError('Response timeout of ', self._responseTimeout, 'ETIMEDOUT');
}, this._responseTimeout);
...
abort = function (){ if (this._aborted) { return this; } this._aborted = true; this.xhr && this.xhr.abort(); // browser this.req && this.req.abort(); // node this.clearTimeout(); this.emit('abort'); return this; }
...
* @api public
*/
RequestBase.prototype.abort = function(){
if (this._aborted) {
return this;
}
this._aborted = true;
this.xhr && this.xhr.abort(); // browser
this.req && this.req.abort(); // node
this.clearTimeout();
this.emit('abort');
return this;
};
/**
...
catch = function (cb) { return this.then(undefined, cb); }
n/a
function _clearTimeout(){ clearTimeout(this._timer); clearTimeout(this._responseTimeoutTimer); delete this._timer; delete this._responseTimeoutTimer; return this; }
...
Request.prototype.callback = function(err, res){
// console.log(this._retries, this._maxRetries)
if (this._maxRetries && this._retries++ < this._maxRetries && shouldRetry(err, res)) {
return this._retry();
}
var fn = this._callback;
this.clearTimeout();
if (err) {
if (this._maxRetries) err.retries = this._retries - 1;
this.emit('error', err);
}
fn(err, res);
...
field = function (name, val) { // name should be either a string or an object. if (null === name || undefined === name) { throw new Error('.field(name, val) name can not be empty'); } if (this._data) { console.error(".field() can't be used if .send() is used. Please use only .send() or only .field() & .attach()"); } if (isObject(name)) { for (var key in name) { this.field(key, name[key]); } return this; } if (Array.isArray(val)) { for (var i in val) { this.field(name, val[i]); } return this; } // val should be defined now if (null === val || undefined === val) { throw new Error('.field(name, val) val can not be empty'); } if ('boolean' === typeof val) { val = '' + val; } this._getFormData().append(name, val); return this; }
...
Tested browsers:
- Latest Firefox, Chrome, Safari
- Latest Android, iPhone
- IE10 through latest. IE9 with polyfills.
Even though IE9 is supported, a polyfill for `window.FormData` is required for `.field()`.
Node 4 or later is required.
# Plugins
SuperAgent is easily extended via plugins.
...
get = function (field){ return this._header[field.toLowerCase()]; }
...
```js
var nocache = require('superagent-no-cache');
var request = require('superagent');
var prefix = require('superagent-prefix')('/static');
request
.get('/some-url')
.query({ action: 'edit', city: 'London' }) // query string
.use(prefix) // Prefixes *only* this request
.use(nocache) // Prevents caching of *only* this request
.end(function(err, res){
// Do something
});
```
...
getHeader = function (field){ return this._header[field.toLowerCase()]; }
n/a
ok = function (cb) { if ('function' !== typeof cb) throw Error("Callback required"); this._okCallback = cb; return this; }
n/a
function parse(fn){ this._parser = fn; return this; }
n/a
redirects = function (n){ this._maxRedirects = n; return this; }
n/a
responseType = function (val){ this._responseType = val; return this; }
...
* which return Blob and ArrayBuffer, respectively.
*
* In Node all values result in Buffer.
*
* Examples:
*
* req.get('/')
* .responseType('blob')
* .end(callback);
*
* @param {String} val
* @return {Request} for chaining
* @api public
*/
...
function retry(count){ // Default to 1 if no count passed or true if (arguments.length === 0 || count === true) count = 1; if (count <= 0) count = 0; this._maxRetries = count; this._retries = 0; return this; }
n/a
send = function (data){ var isObj = isObject(data); var type = this._header['content-type']; if (this._formData) { console.error(".send() can't be used if .attach() or .field() is used. Please use only .send() or only .field() & .attach()"); } if (isObj && !this._data) { if (Array.isArray(data)) { this._data = []; } else if (!this._isHost(data)) { this._data = {}; } } else if (data && this._data && this._isHost(this._data)) { throw Error("Can't merge these send calls"); } // merge if (isObj && isObject(this._data)) { for (var key in data) { this._data[key] = data[key]; } } else if ('string' == typeof data) { // default to x-www-form-urlencoded if (!type) this.type('form'); type = this._header['content-type']; if ('application/x-www-form-urlencoded' == type) { this._data = this._data ? this._data + '&' + data : data; } else { this._data = (this._data || '') + data; } } else { this._data = data; } if (!isObj || this._isHost(data)) { return this; } // default to json if (!type) this.type('json'); return this; }
...
```
Works with [browserify](https://github.com/substack/node-browserify) and should work with [webpack](https://github.com/visionmedia
/superagent/wiki/SuperAgent-for-Webpack)
```js
request
.post('/api/pet')
.send({ name: 'Manny', species: 'cat' })
.set('X-API-Key', 'foobar')
.set('Accept', 'application/json')
.end(function(err, res){
// Calling the end function will send the request
});
```
...
function serialize(fn){ this._serializer = fn; return this; }
n/a
set = function (field, val){ if (isObject(field)) { for (var key in field) { this.set(key, field[key]); } return this; } this._header[field.toLowerCase()] = val; this.header[field] = val; return this; }
...
Works with [browserify](https://github.com/substack/node-browserify) and should work with [webpack](https://github.com/visionmedia
/superagent/wiki/SuperAgent-for-Webpack)
```js
request
.post('/api/pet')
.send({ name: 'Manny', species: 'cat' })
.set('X-API-Key', 'foobar')
.set('Accept', 'application/json')
.end(function(err, res){
// Calling the end function will send the request
});
```
## Supported browsers and Node versions
...
sortQuery = function (sort) { // _sort default to true but otherwise can be a function or boolean this._sort = typeof sort === 'undefined' ? true : sort; return this; }
...
*
* Examples:
*
* // default order
* request.get('/user')
* .query('name=Nick')
* .query('search=Manny')
* .sortQuery()
* .end(callback)
*
* // customized sort function
* request.get('/user')
* .query('name=Nick')
* .query('search=Manny')
* .sortQuery(function(a, b){
...
function then(resolve, reject) { if (!this._fullfilledPromise) { var self = this; if (this._endCalled) { console.warn("Warning: superagent request was sent twice, because both .end() and .then() were called. Never call .end() if you use promises"); } this._fullfilledPromise = new Promise(function(innerResolve, innerReject){ self.end(function(err, res){ if (err) innerReject(err); else innerResolve(res); }); }); } return this._fullfilledPromise.then(resolve, reject); }
...
* @return {Request}
*/
RequestBase.prototype.then = function then(resolve, reject) {
if (!this._fullfilledPromise) {
var self = this;
if (this._endCalled) {
console.warn("Warning: superagent request was sent twice, because both .end() and .
then() were called. Never call .end() if you use promises");
}
this._fullfilledPromise = new Promise(function(innerResolve, innerReject){
self.end(function(err, res){
if (err) innerReject(err); else innerResolve(res);
});
});
}
...
function timeout(options){ if (!options || 'object' !== typeof options) { this._timeout = options; this._responseTimeout = 0; return this; } for(var option in options) { switch(option) { case 'deadline': this._timeout = options.deadline; break; case 'response': this._responseTimeout = options.response; break; default: console.warn("Unknown timeout option", option); } } return this; }
n/a
toJSON = function (){ return { method: this.method, url: this.url, data: this._data, headers: this._header }; }
n/a
unset = function (field){ delete this._header[field.toLowerCase()]; delete this.header[field]; return this; }
...
/**
* Remove header `field`.
* Case-insensitive.
*
* Example:
*
* req.get('/')
* .unset('User-Agent')
* .end(callback);
*
* @param {String} field
*/
RequestBase.prototype.unset = function(field){
delete this._header[field.toLowerCase()];
delete this.header[field];
...
function use(fn) { fn(this); return this; }
...
var nocache = require('superagent-no-cache');
var request = require('superagent');
var prefix = require('superagent-prefix')('/static');
request
.get('/some-url')
.query({ action: 'edit', city: 'London' }) // query string
.use(prefix) // Prefixes *only* this request
.use(nocache) // Prevents caching of *only* this request
.end(function(err, res){
// Do something
});
```
Existing plugins:
...
withCredentials = function (on){ // This is browser-only functionality. Node side is no-op. if(on==undefined) on = true; this._withCredentials = on; return this; }
n/a
function ResponseBase(obj) { if (obj) return mixin(obj); }
n/a
_setHeaderProperties = function (header){ // TODO: moar! // TODO: make this a util // content-type var ct = header['content-type'] || ''; this.type = utils.type(ct); // params var params = utils.params(ct); for (var key in params) this[key] = params[key]; this.links = {}; // links try { if (header.link) { this.links = utils.parseLinks(header.link); } } catch (err) { // ignore } }
...
}
this._setStatusProperties(status);
this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders());
// getAllResponseHeaders sometimes falsely returns "" for CORS requests, but
// getResponseHeader still works. so we get content-type even if getting
// other headers fails.
this.header['content-type'] = this.xhr.getResponseHeader('content-type');
this._setHeaderProperties(this.header);
if (null === this.text && req._responseType) {
this.body = this.xhr.response;
} else {
this.body = this.req.method != 'HEAD'
? this._parseBody(this.text ? this.text : this.xhr.response)
: null;
...
_setStatusProperties = function (status){ var type = status / 100 | 0; // status / class this.status = this.statusCode = status; this.statusType = type; // basics this.info = 1 == type; this.ok = 2 == type; this.redirect = 3 == type; this.clientError = 4 == type; this.serverError = 5 == type; this.error = (4 == type || 5 == type) ? this.toError() : false; // sugar this.accepted = 202 == status; this.noContent = 204 == status; this.badRequest = 400 == status; this.unauthorized = 401 == status; this.notAcceptable = 406 == status; this.forbidden = 403 == status; this.notFound = 404 == status; }
...
: null;
this.statusText = this.req.xhr.statusText;
var status = this.xhr.status;
// handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request
if (status === 1223) {
status = 204;
}
this._setStatusProperties(status);
this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders());
// getAllResponseHeaders sometimes falsely returns "" for CORS requests, but
// getResponseHeader still works. so we get content-type even if getting
// other headers fails.
this.header['content-type'] = this.xhr.getResponseHeader('content-type');
this._setHeaderProperties(this.header);
...
get = function (field){ return this.header[field.toLowerCase()]; }
...
```js
var nocache = require('superagent-no-cache');
var request = require('superagent');
var prefix = require('superagent-prefix')('/static');
request
.get('/some-url')
.query({ action: 'edit', city: 'London' }) // query string
.use(prefix) // Prefixes *only* this request
.use(nocache) // Prevents caching of *only* this request
.end(function(err, res){
// Do something
});
```
...
superagent = function (method, url) { // callback if ('function' == typeof url) { return new exports.Request('GET', method).end(url); } // url first if (1 == arguments.length) { return new exports.Request('GET', method); } return new exports.Request(method, url); }
n/a
function Request(method, url) { var self = this; this._query = this._query || []; this.method = method; this.url = url; this.header = {}; // preserves header name case this._header = {}; // coerces header names to lowercase this.on('end', function(){ var err = null; var res = null; try { res = new Response(self); } catch(e) { err = new Error('Parser is unable to parse the response'); err.parse = true; err.original = e; // issue #675: return the raw response if the response parsing fails if (self.xhr) { // ie9 doesn't have 'response' property err.rawResponse = typeof self.xhr.responseType == 'undefined' ? self.xhr.responseText : self.xhr.response; // issue #876: return the http status code if the response parsing fails err.status = self.xhr.status ? self.xhr.status : null; err.statusCode = err.status; // backwards-compat only } else { err.rawResponse = null; err.status = null; } return self.callback(err); } self.emit('response', res); var new_err; try { if (!self._isResponseOK(res)) { new_err = new Error(res.statusText || 'Unsuccessful HTTP response'); new_err.original = err; new_err.response = res; new_err.status = res.status; } } catch(e) { new_err = e; // #985 touching res may cause INVALID_STATE_ERR on old Android } // #1000 don't catch errors from the callback to avoid double calling it if (new_err) { self.callback(new_err, res); } else { self.callback(null, res); } }); }
...
/**
* Expose `request`.
*/
var request = exports = module.exports = function(method, url) {
// callback
if ('function' == typeof url) {
return new exports.Request('GET', method).end(url);
}
// url first
if (1 == arguments.length) {
return new exports.Request('GET', method);
}
...
function Response(req) { this.req = req; this.xhr = this.req.xhr; // responseText is accessible only if responseType is '' or 'text' and on older browsers this.text = ((this.req.method !='HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text')) || typeof this.xhr .responseType === 'undefined') ? this.xhr.responseText : null; this.statusText = this.req.xhr.statusText; var status = this.xhr.status; // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request if (status === 1223) { status = 204; } this._setStatusProperties(status); this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders()); // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but // getResponseHeader still works. so we get content-type even if getting // other headers fails. this.header['content-type'] = this.xhr.getResponseHeader('content-type'); this._setHeaderProperties(this.header); if (null === this.text && req._responseType) { this.body = this.xhr.response; } else { this.body = this.req.method != 'HEAD' ? this._parseBody(this.text ? this.text : this.xhr.response) : null; } }
n/a
function del(url, data, fn){ var req = request('DELETE', url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); if (fn) req.end(fn); return req; }
n/a
function del(url, data, fn){ var req = request('DELETE', url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); if (fn) req.end(fn); return req; }
n/a
get = function (url, data, fn){ var req = request('GET', url); if ('function' == typeof data) fn = data, data = null; if (data) req.query(data); if (fn) req.end(fn); return req; }
...
```js
var nocache = require('superagent-no-cache');
var request = require('superagent');
var prefix = require('superagent-prefix')('/static');
request
.get('/some-url')
.query({ action: 'edit', city: 'London' }) // query string
.use(prefix) // Prefixes *only* this request
.use(nocache) // Prevents caching of *only* this request
.end(function(err, res){
// Do something
});
```
...
getXHR = function () { if (root.XMLHttpRequest && (!root.location || 'file:' != root.location.protocol || !root.ActiveXObject)) { return new XMLHttpRequest; } else { try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {} try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {} try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {} try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {} } throw Error("Browser-only verison of superagent could not find XHR"); }
...
this._appendQueryString();
return this._end();
};
Request.prototype._end = function() {
var self = this;
var xhr = this.xhr = request.getXHR();
var data = this._formData || this._data;
this._setTimeouts();
// state change
xhr.onreadystatechange = function(){
var readyState = xhr.readyState;
...
head = function (url, data, fn){ var req = request('HEAD', url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); if (fn) req.end(fn); return req; }
n/a
options = function (url, data, fn){ var req = request('OPTIONS', url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); if (fn) req.end(fn); return req; }
n/a
function parseString(str) { var obj = {}; var pairs = str.split('&'); var pair; var pos; for (var i = 0, len = pairs.length; i < len; ++i) { pair = pairs[i]; pos = pair.indexOf('='); if (pos == -1) { obj[decodeURIComponent(pair)] = ''; } else { obj[decodeURIComponent(pair.slice(0, pos))] = decodeURIComponent(pair.slice(pos + 1)); } } return obj; }
n/a
patch = function (url, data, fn){ var req = request('PATCH', url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); if (fn) req.end(fn); return req; }
n/a
post = function (url, data, fn){ var req = request('POST', url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); if (fn) req.end(fn); return req; }
...
$ npm install superagent
```
Works with [browserify](https://github.com/substack/node-browserify) and should work with [webpack](https://github.com/visionmedia
/superagent/wiki/SuperAgent-for-Webpack)
```js
request
.post('/api/pet')
.send({ name: 'Manny', species: 'cat' })
.set('X-API-Key', 'foobar')
.set('Accept', 'application/json')
.end(function(err, res){
// Calling the end function will send the request
});
```
...
put = function (url, data, fn){ var req = request('PUT', url); if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); if (fn) req.end(fn); return req; }
n/a
function serialize(obj) { if (!isObject(obj)) return obj; var pairs = []; for (var key in obj) { pushEncodedKeyValuePair(pairs, key, obj[key]); } return pairs.join('&'); }
n/a
cleanHeader = function (header, shouldStripCookie){ delete header['content-type']; delete header['content-length']; delete header['transfer-encoding']; delete header['host']; if (shouldStripCookie) { delete header['cookie']; } return header; }
n/a
params = function (str){ return str.split(/ *; */).reduce(function(obj, str){ var parts = str.split(/ *= */); var key = parts.shift(); var val = parts.shift(); if (key && val) obj[key] = val; return obj; }, {}); }
...
// TODO: make this a util
// content-type
var ct = header['content-type'] || '';
this.type = utils.type(ct);
// params
var params = utils.params(ct);
for (var key in params) this[key] = params[key];
this.links = {};
// links
try {
if (header.link) {
...
parseLinks = function (str){ return str.split(/ *, */).reduce(function(obj, str){ var parts = str.split(/ *; */); var url = parts[0].slice(1, -1); var rel = parts[1].split(/ *= */)[1].slice(1, -1); obj[rel] = url; return obj; }, {}); }
...
for (var key in params) this[key] = params[key];
this.links = {};
// links
try {
if (header.link) {
this.links = utils.parseLinks(header.link);
}
} catch (err) {
// ignore
}
};
/**
...
type = function (str){ return str.split(/ *; */).shift(); }
...
* Set Content-Type to `type`, mapping values from `request.types`.
*
* Examples:
*
* superagent.types.xml = 'application/xml';
*
* request.post('/')
* .type('xml')
* .send(xmlstring)
* .end(callback);
*
* request.post('/')
* .type('application/xml')
* .send(xmlstring)
* .end(callback);
...