UNPKG

falcor-http-datasource

Version:

This package contains falcor components for use in browsers.

222 lines (182 loc) 5.84 kB
'use strict'; var getXMLHttpRequest = require('./getXMLHttpRequest'); var getCORSRequest = require('./getCORSRequest'); var hasOwnProp = Object.prototype.hasOwnProperty; var noop = function() {}; function Observable() {} Observable.create = function(subscribe) { var o = new Observable(); o.subscribe = function(onNext, onError, onCompleted) { var observer; var disposable; if (typeof onNext === 'function') { observer = { onNext: onNext, onError: (onError || noop), onCompleted: (onCompleted || noop) }; } else { observer = onNext; } disposable = subscribe(observer); if (typeof disposable === 'function') { return { dispose: disposable }; } else { return disposable; } }; return o; }; function request(method, options, context) { return Observable.create(function requestObserver(observer) { var config = { method: method || 'GET', crossDomain: false, async: true, headers: {}, responseType: 'json' }; var xhr, isDone, headers, header, prop; for (prop in options) { if (hasOwnProp.call(options, prop)) { config[prop] = options[prop]; } } // Add request with Headers if (!config.crossDomain && !config.headers['X-Requested-With']) { config.headers['X-Requested-With'] = 'XMLHttpRequest'; } // allow the user to mutate the config open if (context.onBeforeRequest != null) { context.onBeforeRequest(config); } // create xhr try { xhr = config.crossDomain ? getCORSRequest() : getXMLHttpRequest(); } catch (err) { observer.onError(err); } try { // Takes the url and opens the connection if (config.user) { xhr.open(config.method, config.url, config.async, config.user, config.password); } else { xhr.open(config.method, config.url, config.async); } // Sets timeout information xhr.timeout = config.timeout; // Anything but explicit false results in true. xhr.withCredentials = config.withCredentials !== false; // Fills the request headers headers = config.headers; for (header in headers) { if (hasOwnProp.call(headers, header)) { xhr.setRequestHeader(header, headers[header]); } } if (config.responseType) { try { xhr.responseType = config.responseType; } catch (e) { // WebKit added support for the json responseType value on 09/03/2013 // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are // known to throw when setting the value "json" as the response type. Other older // browsers implementing the responseType // // The json response type can be ignored if not supported, because JSON payloads are // parsed on the client-side regardless. if (config.responseType !== 'json') { throw e; } } } xhr.onreadystatechange = function onreadystatechange(e) { // Complete if (xhr.readyState === 4) { if (!isDone) { isDone = true; onXhrLoad(observer, xhr, e); } } }; // Timeout xhr.ontimeout = function ontimeout(e) { if (!isDone) { isDone = true; onXhrError(observer, xhr, 'timeout error', e); } }; // Send Request xhr.send(config.data); } catch (e) { observer.onError(e); } // Dispose return function dispose() { // Doesn't work in IE9 if (!isDone && xhr.readyState !== 4) { isDone = true; xhr.abort(); } };//Dispose }); } /* * General handling of ultimate failure (after appropriate retries) */ function _handleXhrError(observer, textStatus, errorThrown) { // IE9: cross-domain request may be considered errors if (!errorThrown) { errorThrown = new Error(textStatus); } observer.onError(errorThrown); } function onXhrLoad(observer, xhr, e) { var responseData, responseObject, responseType; // If there's no observer, the request has been (or is being) cancelled. if (xhr && observer) { responseType = xhr.responseType; // responseText is the old-school way of retrieving response (supported by IE8 & 9) // response/responseType properties were introduced in XHR Level2 spec (supported by IE10) responseData = ('response' in xhr) ? xhr.response : xhr.responseText; // normalize IE9 bug (http://bugs.jquery.com/ticket/1450) var status = (xhr.status === 1223) ? 204 : xhr.status; if (status >= 200 && status <= 399) { try { if (responseType !== 'json') { responseData = JSON.parse(responseData || ''); } if (typeof responseData === 'string') { responseData = JSON.parse(responseData || ''); } } catch (e) { _handleXhrError(observer, 'invalid json', e); } observer.onNext(responseData); observer.onCompleted(); return; } else if (status === 401 || status === 403 || status === 407) { return _handleXhrError(observer, responseData); } else if (status === 410) { // TODO: Retry ? return _handleXhrError(observer, responseData); } else if (status === 408 || status === 504) { // TODO: Retry ? return _handleXhrError(observer, responseData); } else { return _handleXhrError(observer, responseData || ('Response code ' + status)); }//if }//if }//onXhrLoad function onXhrError(observer, xhr, status, e) { _handleXhrError(observer, status || xhr.statusText || 'request error', e); } module.exports = request;