Created
September 18, 2012 04:02
-
-
Save euforic/3741184 to your computer and use it in GitHub Desktop.
API Builder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* apibuilder | |
* Copyright (c) 2012 Christian Sullivan <[email protected]> | |
* MIT Licensed | |
*/ | |
var request = require('superagent'); | |
/** | |
* Module Exports | |
*/ | |
var api = module.exports | |
, _debug = false; | |
/** | |
* Enable Debug Output | |
* | |
* @api public | |
*/ | |
api.enableDebug = function(){ | |
_debug = true; | |
}; | |
/** | |
* API Base URL | |
*/ | |
var BASE_URL = 'https://REQUEST_URL'; | |
/** | |
* API Schema | |
*/ | |
var apiSchema = { | |
user:[ | |
{ method:'create' , verb:'PUT' } | |
, { method:'login' , verb:'POST' } | |
, { method:'logout' , verb:'GET' } | |
, { method:'show' , verb:'GET' } | |
, { method:'showMe' , verb:'GET' } | |
, { method:'update' , verb:'POST' } | |
] | |
, job:[ | |
{ method:'create' , verb:'PUT' } | |
, { method:'update' , verb:'POST' } | |
, { method:'remove' , verb:'DELETE' } | |
, { method:'show' , verb:'GET' } | |
]}; | |
/** | |
* Create API Namespace and loop through methods | |
*/ | |
for(var key in apiSchema){ | |
createMethod(key, apiSchema[key]); | |
} | |
/** | |
* Create Methods for Namespace | |
* | |
* @param {String} key | |
* @package {Array} val | |
* @return {Boolean} | |
* @api private | |
*/ | |
function createMethod(key,val){ | |
var ns = api[key] = {}; | |
val.forEach(function(e){ | |
ns[e.method] = function(data,cb){ | |
var url = (e.url) ? e.url : BASE_URL; | |
url = url +'/'+ ((e.path) ? e.path : e.method); | |
var verb = e.verb || 'GET'; | |
// Debug Output | |
if(_debug) { e.url = url; console.log({request:e}); } | |
request(verb, url) | |
.set('Accept', 'application/json') | |
.send(data) | |
.end(function(response){ | |
cb(response); | |
// Debug Output | |
if(_debug){ console.log({response:response}); } | |
}); | |
}; | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* SAMPLE USAGE | |
*/ | |
var API = require('apibuilder'); | |
API.user.create({firstname:'Teddy', lastname:'Tester'}, function(res){ | |
// Do something with response | |
}); | |
API.user.login({user:'euforic', password:'mypassword'}, function(res){ | |
// Do something with response | |
}); | |
API.job.create({name:'titanium engineer', location:'Newport Beach, CA'}, function(res){ | |
// Do something with response | |
}); | |
API.job.update({id:123456, lastname:'Tester'}, function(res){ | |
// Do something with response | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Superagent - https://github.com/visionmedia/superagent | |
* Modified version to work with titanium also | |
*/ | |
/** | |
* Module exports. | |
*/ | |
/** | |
* Check if `obj` is an array. | |
*/ | |
function isArray(obj) { | |
return '[object Array]' == {}.toString.call(obj); | |
} | |
/** | |
* Event emitter constructor. | |
* | |
* @api public. | |
*/ | |
function EventEmitter(){} | |
/** | |
* Adds a listener. | |
* | |
* @api public | |
*/ | |
EventEmitter.prototype.on = function (name, fn) { | |
if (!this.$events) { | |
this.$events = {}; | |
} | |
if (!this.$events[name]) { | |
this.$events[name] = fn; | |
} else if (isArray(this.$events[name])) { | |
this.$events[name].push(fn); | |
} else { | |
this.$events[name] = [this.$events[name], fn]; | |
} | |
return this; | |
}; | |
EventEmitter.prototype.addListener = EventEmitter.prototype.on; | |
/** | |
* Adds a volatile listener. | |
* | |
* @api public | |
*/ | |
EventEmitter.prototype.once = function (name, fn) { | |
var self = this; | |
function on () { | |
self.removeListener(name, on); | |
fn.apply(this, arguments); | |
} | |
on.listener = fn; | |
this.on(name, on); | |
return this; | |
}; | |
/** | |
* Removes a listener. | |
* | |
* @api public | |
*/ | |
EventEmitter.prototype.removeListener = function (name, fn) { | |
if (this.$events && this.$events[name]) { | |
var list = this.$events[name]; | |
if (isArray(list)) { | |
var pos = -1; | |
for (var i = 0, l = list.length; i < l; i++) { | |
if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { | |
pos = i; | |
break; | |
} | |
} | |
if (pos < 0) { | |
return this; | |
} | |
list.splice(pos, 1); | |
if (!list.length) { | |
delete this.$events[name]; | |
} | |
} else if (list === fn || (list.listener && list.listener === fn)) { | |
delete this.$events[name]; | |
} | |
} | |
return this; | |
}; | |
/** | |
* Removes all listeners for an event. | |
* | |
* @api public | |
*/ | |
EventEmitter.prototype.removeAllListeners = function (name) { | |
if (name === undefined) { | |
this.$events = {}; | |
return this; | |
} | |
if (this.$events && this.$events[name]) { | |
this.$events[name] = null; | |
} | |
return this; | |
}; | |
/** | |
* Gets all listeners for a certain event. | |
* | |
* @api publci | |
*/ | |
EventEmitter.prototype.listeners = function (name) { | |
if (!this.$events) { | |
this.$events = {}; | |
} | |
if (!this.$events[name]) { | |
this.$events[name] = []; | |
} | |
if (!isArray(this.$events[name])) { | |
this.$events[name] = [this.$events[name]]; | |
} | |
return this.$events[name]; | |
}; | |
/** | |
* Emits an event. | |
* | |
* @api public | |
*/ | |
EventEmitter.prototype.emit = function (name) { | |
if (!this.$events) { | |
return false; | |
} | |
var handler = this.$events[name]; | |
if (!handler) { | |
return false; | |
} | |
var args = [].slice.call(arguments, 1); | |
if ('function' == typeof handler) { | |
handler.apply(this, args); | |
} else if (isArray(handler)) { | |
var listeners = handler.slice(); | |
for (var i = 0, l = listeners.length; i < l; i++) { | |
listeners[i].apply(this, args); | |
} | |
} else { | |
return false; | |
} | |
return true; | |
}; | |
/*! | |
* superagent | |
* Copyright (c) 2012 TJ Holowaychuk <[email protected]> | |
* MIT Licensed | |
*/ | |
;(function(){ | |
var Emitter = 'undefined' == typeof exports | |
? EventEmitter | |
: require('EventEmitter').EventEmitter2; | |
/** | |
* Noop. | |
*/ | |
function noop(){} | |
/** | |
* Determine XHR. | |
*/ | |
function getXHR() { | |
if (Titanium) { | |
try { return Titanium.Network.createHTTPClient(); } catch(e) {} | |
} else if (window.XMLHttpRequest | |
&& ('file:' != window.location.protocol || !window.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) {} | |
} | |
return false; | |
} | |
/** | |
* Removes leading and trailing whitespace, added to support IE. | |
* | |
* @param {String} s | |
* @return {String} | |
* @api private | |
*/ | |
var trim = ''.trim | |
? function(s) { return s.trim(); } | |
: function(s) { return s.replace(/(^\s*|\s*$)/g, ''); }; | |
/** | |
* Check if `obj` is a function. | |
* | |
* @param {Mixed} obj | |
* @return {Boolean} | |
* @api private | |
*/ | |
function isFunction(obj) { | |
return 'function' == typeof obj; | |
} | |
/** | |
* Check if `obj` is an object. | |
* | |
* @param {Object} obj | |
* @return {Boolean} | |
* @api private | |
*/ | |
function isObject(obj) { | |
return null != obj && 'object' == typeof obj; | |
} | |
/** | |
* Serialize the given `obj`. | |
* | |
* @param {Object} obj | |
* @return {String} | |
* @api private | |
*/ | |
function serialize(obj) { | |
if (!isObject(obj)) return obj; | |
var pairs = []; | |
for (var key in obj) { | |
pairs.push(encodeURIComponent(key) | |
+ '=' + encodeURIComponent(obj[key])); | |
} | |
return pairs.join('&'); | |
} | |
/** | |
* Expose serialization method. | |
*/ | |
request.serializeObject = serialize; | |
/** | |
* Parse the given x-www-form-urlencoded `str`. | |
* | |
* @param {String} str | |
* @return {Object} | |
* @api private | |
*/ | |
function parseString(str) { | |
var obj = {} | |
, pairs = str.split('&') | |
, parts | |
, pair; | |
for (var i = 0, len = pairs.length; i < len; ++i) { | |
pair = pairs[i]; | |
parts = pair.split('='); | |
obj[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); | |
} | |
return obj; | |
} | |
/** | |
* Expose parser. | |
*/ | |
request.parseString = parseString; | |
/** | |
* Default MIME type map. | |
* | |
* superagent.types.xml = 'application/xml'; | |
* | |
*/ | |
request.types = { | |
html: 'text/html' | |
, json: 'application/json' | |
, urlencoded: 'application/x-www-form-urlencoded' | |
, 'form': 'application/x-www-form-urlencoded' | |
, 'form-data': 'application/x-www-form-urlencoded' | |
}; | |
/** | |
* Default serialization map. | |
* | |
* superagent.serialize['application/xml'] = function(obj){ | |
* return 'generated xml here'; | |
* }; | |
* | |
*/ | |
request.serialize = { | |
'application/x-www-form-urlencoded': serialize | |
, 'application/json': JSON.stringify | |
}; | |
/** | |
* Default parsers. | |
* | |
* superagent.parse['application/xml'] = function(str){ | |
* return { object parsed from str }; | |
* }; | |
* | |
*/ | |
request.parse = { | |
'application/x-www-form-urlencoded': parseString | |
, 'application/json': JSON.parse | |
}; | |
/** | |
* Parse the given header `str` into | |
* an object containing the mapped fields. | |
* | |
* @param {String} str | |
* @return {Object} | |
* @api private | |
*/ | |
function parseHeader(str) { | |
var lines = str.split(/\r?\n/) | |
, fields = {} | |
, index | |
, line | |
, field | |
, val; | |
lines.pop(); // trailing CRLF | |
for (var i = 0, len = lines.length; i < len; ++i) { | |
line = lines[i]; | |
index = line.indexOf(':'); | |
field = line.slice(0, index).toLowerCase(); | |
val = trim(line.slice(index + 1)); | |
fields[field] = val; | |
} | |
return fields; | |
} | |
/** | |
* Return the mime type for the given `str`. | |
* | |
* @param {String} str | |
* @return {String} | |
* @api private | |
*/ | |
function type(str){ | |
return str.split(/ *; */).shift(); | |
}; | |
/** | |
* Return header field parameters. | |
* | |
* @param {String} str | |
* @return {Object} | |
* @api private | |
*/ | |
function params(str){ | |
return str.split(/ *; */).reduce(function(obj, str){ | |
var parts = str.split(/ *= */) | |
, key = parts.shift() | |
, val = parts.shift(); | |
if (key && val) obj[key] = val; | |
return obj; | |
}, {}); | |
}; | |
/** | |
* Initialize a new `Response` with the given `xhr`. | |
* | |
* - set flags (.ok, .error, etc) | |
* - parse header | |
* | |
* Examples: | |
* | |
* Aliasing `superagent` as `request` is nice: | |
* | |
* request = superagent; | |
* | |
* We can use the promise-like API, or pass callbacks: | |
* | |
* request.get('/').end(function(res){}); | |
* request.get('/', function(res){}); | |
* | |
* Sending data can be chained: | |
* | |
* request | |
* .post('/user') | |
* .send({ name: 'tj' }) | |
* .end(function(res){}); | |
* | |
* Or passed to `.send()`: | |
* | |
* request | |
* .post('/user') | |
* .send({ name: 'tj' }, function(res){}); | |
* | |
* Or passed to `.post()`: | |
* | |
* request | |
* .post('/user', { name: 'tj' }) | |
* .end(function(res){}); | |
* | |
* Or further reduced to a single call for simple cases: | |
* | |
* request | |
* .post('/user', { name: 'tj' }, function(res){}); | |
* | |
* @param {XMLHTTPRequest} xhr | |
* @param {Object} options | |
* @api private | |
*/ | |
function Response(xhr, options) { | |
options = options || {}; | |
this.xhr = xhr; | |
this.text = xhr.responseText; | |
this.setStatusProperties(xhr.status); | |
this.header = (Ti) ? { 'content-type' : xhr.getResponseHeader('Content-Type') } : parseHeader(xhr.getAllResponseHeaders()); | |
this.setHeaderProperties(this.header); | |
this.body = this.parseBody(this.text); | |
} | |
/** | |
* Set header related properties: | |
* | |
* - `.type` the content type without params | |
* | |
* A response of "Content-Type: text/plain; charset=utf-8" | |
* will provide you with a `.type` of "text/plain". | |
* | |
* @param {Object} header | |
* @api private | |
*/ | |
Response.prototype.setHeaderProperties = function(header){ | |
// content-type | |
var ct = this.header['content-type'] || ''; | |
this.type = type(ct); | |
// params | |
var obj = params(ct); | |
for (var key in obj) this[key] = obj[key]; | |
}; | |
/** | |
* Parse the given body `str`. | |
* | |
* Used for auto-parsing of bodies. Parsers | |
* are defined on the `superagent.parse` object. | |
* | |
* @param {String} str | |
* @return {Mixed} | |
* @api private | |
*/ | |
Response.prototype.parseBody = function(str){ | |
var parse = request.parse[this.type]; | |
return parse | |
? parse(str) | |
: null; | |
}; | |
/** | |
* Set flags such as `.ok` based on `status`. | |
* | |
* For example a 2xx response will give you a `.ok` of __true__ | |
* whereas 5xx will be __false__ and `.error` will be __true__. The | |
* `.clientError` and `.serverError` are also available to be more | |
* specific, and `.statusType` is the class of error ranging from 1..5 | |
* sometimes useful for mapping respond colors etc. | |
* | |
* "sugar" properties are also defined for common cases. Currently providing: | |
* | |
* - .noContent | |
* - .badRequest | |
* - .unauthorized | |
* - .notAcceptable | |
* - .notFound | |
* | |
* @param {Number} status | |
* @api private | |
*/ | |
Response.prototype.setStatusProperties = function(status){ | |
var type = status / 100 | 0; | |
// status / class | |
this.status = status; | |
this.statusType = type; | |
// basics | |
this.info = 1 == type; | |
this.ok = 2 == type; | |
this.clientError = 4 == type; | |
this.serverError = 5 == type; | |
this.error = 4 == type || 5 == type; | |
// sugar | |
this.accepted = 202 == status; | |
this.noContent = 204 == status || 1223 == status; | |
this.badRequest = 400 == status; | |
this.unauthorized = 401 == status; | |
this.notAcceptable = 406 == status; | |
this.notFound = 404 == status; | |
}; | |
/** | |
* Expose `Response`. | |
*/ | |
request.Response = Response; | |
/** | |
* Initialize a new `Request` with the given `method` and `url`. | |
* | |
* @param {String} method | |
* @param {String} url | |
* @api public | |
*/ | |
function Request(method, url) { | |
var self = this; | |
Emitter.call(this); | |
this.method = method; | |
this.url = url; | |
this.header = {}; | |
this.set('X-Requested-With', 'XMLHttpRequest'); | |
this.on('end', function(){ | |
self.callback(new Response(self.xhr)); | |
}); | |
} | |
/** | |
* Inherit from `Emitter.prototype`. | |
*/ | |
Request.prototype = new Emitter; | |
Request.prototype.constructor = Request; | |
/** | |
* Set header `field` to `val`, or multiple fields with one object. | |
* | |
* Examples: | |
* | |
* req.get('/') | |
* .set('Accept', 'application/json') | |
* .set('X-API-Key', 'foobar') | |
* .end(callback); | |
* | |
* req.get('/') | |
* .set({ Accept: 'application/json', 'X-API-Key': 'foobar' }) | |
* .end(callback); | |
* | |
* @param {String|Object} field | |
* @param {String} val | |
* @return {Request} for chaining | |
* @api public | |
*/ | |
Request.prototype.set = function(field, val){ | |
if (isObject(field)) { | |
for (var key in field) { | |
this.set(key, field[key]); | |
} | |
return this; | |
} | |
this.header[field.toLowerCase()] = val; | |
return this; | |
}; | |
/** | |
* 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); | |
* | |
* @param {String} type | |
* @return {Request} for chaining | |
* @api public | |
*/ | |
Request.prototype.type = function(type){ | |
this.set('Content-Type', request.types[type] || type); | |
return this; | |
}; | |
/** | |
* Add `obj` to the query-string, later formatted | |
* in `.end()`. | |
* | |
* @param {Object} obj | |
* @return {Request} for chaining | |
* @api public | |
*/ | |
Request.prototype.query = function(obj){ | |
this._query = this._query || {}; | |
for (var key in obj) { | |
this._query[key] = obj[key]; | |
} | |
return this; | |
}; | |
/** | |
* Send `data`, defaulting the `.type()` to "json" when | |
* an object is given. | |
* | |
* Examples: | |
* | |
* // querystring | |
* request.get('/search') | |
* .send({ search: 'query' }) | |
* .end(callback) | |
* | |
* // multiple data "writes" | |
* request.get('/search') | |
* .send({ search: 'query' }) | |
* .send({ range: '1..5' }) | |
* .send({ order: 'desc' }) | |
* .end(callback) | |
* | |
* // manual json | |
* request.post('/user') | |
* .type('json') | |
* .send('{"name":"tj"}) | |
* .end(callback) | |
* | |
* // auto json | |
* request.post('/user') | |
* .send({ name: 'tj' }) | |
* .end(callback) | |
* | |
* // manual x-www-form-urlencoded | |
* request.post('/user') | |
* .type('form') | |
* .send('name=tj') | |
* .end(callback) | |
* | |
* // auto x-www-form-urlencoded | |
* request.post('/user') | |
* .type('form') | |
* .send({ name: 'tj' }) | |
* .end(callback) | |
* | |
* // defaults to x-www-form-urlencoded | |
* request.post('/user') | |
* .send('name=tobi') | |
* .send('species=ferret') | |
* .end(callback) | |
* | |
* @param {String|Object} data | |
* @return {Request} for chaining | |
* @api public | |
*/ | |
Request.prototype.send = function(data){ | |
if ('GET' == this.method) return this.query(data); | |
var obj = isObject(data); | |
var type = this.header['content-type']; | |
// merge | |
if (obj && isObject(this._data)) { | |
for (var key in data) { | |
this._data[key] = data[key]; | |
} | |
} else if ('string' == typeof data) { | |
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 (!obj) return this; | |
if (!type) this.type('json'); | |
return this; | |
}; | |
/** | |
* Initiate request, invoking callback `fn(res)` | |
* with an instanceof `Response`. | |
* | |
* @param {Function} fn | |
* @return {Request} for chaining | |
* @api public | |
*/ | |
Request.prototype.end = function(fn){ | |
var self = this | |
, xhr = this.xhr = getXHR() | |
, query = this._query | |
, data = this._data; | |
// store callback | |
this.callback = fn || noop; | |
// state change | |
xhr.onreadystatechange = function(){ | |
if (4 == xhr.readyState) self.emit('end'); | |
}; | |
// querystring | |
if (query) { | |
query = request.serializeObject(query); | |
this.url += ~this.url.indexOf('?') | |
? '&' + query | |
: '?' + query; | |
} | |
// initiate request | |
xhr.open(this.method, this.url, true); | |
// body | |
if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data) { | |
// serialize stuff | |
var serialize = request.serialize[this.header['content-type']]; | |
if (serialize) data = serialize(data); | |
} | |
// set header fields | |
for (var field in this.header) { | |
xhr.setRequestHeader(field, this.header[field]); | |
} | |
// send stuff | |
xhr.send(data); | |
return this; | |
}; | |
/** | |
* Expose `Request`. | |
*/ | |
request.Request = Request; | |
/** | |
* Issue a request: | |
* | |
* Examples: | |
* | |
* request('GET', '/users').end(callback) | |
* request('/users').end(callback) | |
* request('/users', callback) | |
* | |
* @param {String} method | |
* @param {String|Function} url or callback | |
* @return {Request} | |
* @api public | |
*/ | |
function request(method, url) { | |
// callback | |
if ('function' == typeof url) { | |
return new Request('GET', method).end(url); | |
} | |
// url first | |
if (1 == arguments.length) { | |
return new Request('GET', method); | |
} | |
return new Request(method, url); | |
} | |
/** | |
* GET `url` with optional callback `fn(res)`. | |
* | |
* @param {String} url | |
* @param {Mixed} data | |
* @param {Function} fn | |
* @return {Request} | |
* @api public | |
*/ | |
request.get = function(url, data, fn){ | |
var req = request('GET', url); | |
if (isFunction(data)) fn = data, data = null; | |
if (data) req.send(data); | |
if (fn) req.end(fn); | |
return req; | |
}; | |
/** | |
* GET `url` with optional callback `fn(res)`. | |
* | |
* @param {String} url | |
* @param {Mixed} data | |
* @param {Function} fn | |
* @return {Request} | |
* @api public | |
*/ | |
request.head = function(url, data, fn){ | |
var req = request('HEAD', url); | |
if (isFunction(data)) fn = data, data = null; | |
if (data) req.send(data); | |
if (fn) req.end(fn); | |
return req; | |
}; | |
/** | |
* DELETE `url` with optional callback `fn(res)`. | |
* | |
* @param {String} url | |
* @param {Function} fn | |
* @return {Request} | |
* @api public | |
*/ | |
request.del = function(url, fn){ | |
var req = request('DELETE', url); | |
if (fn) req.end(fn); | |
return req; | |
}; | |
/** | |
* PATCH `url` with optional `data` and callback `fn(res)`. | |
* | |
* @param {String} url | |
* @param {Mixed} data | |
* @param {Function} fn | |
* @return {Request} | |
* @api public | |
*/ | |
request.patch = function(url, data, fn){ | |
var req = request('PATCH', url); | |
if (data) req.send(data); | |
if (fn) req.end(fn); | |
return req; | |
}; | |
/** | |
* POST `url` with optional `data` and callback `fn(res)`. | |
* | |
* @param {String} url | |
* @param {Mixed} data | |
* @param {Function} fn | |
* @return {Request} | |
* @api public | |
*/ | |
request.post = function(url, data, fn){ | |
var req = request('POST', url); | |
if (data) req.send(data); | |
if (fn) req.end(fn); | |
return req; | |
}; | |
/** | |
* PUT `url` with optional `data` and callback `fn(res)`. | |
* | |
* @param {String} url | |
* @param {Mixed} data | |
* @param {Function} fn | |
* @return {Request} | |
* @api public | |
*/ | |
request.put = function(url, data, fn){ | |
var req = request('PUT', url); | |
if (data) req.send(data); | |
if (fn) req.end(fn); | |
return req; | |
}; | |
// expose | |
if ('undefined' == typeof exports) { | |
window.request = window.superagent = request; | |
} else { | |
module.exports = request; | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment