Skip to content

Rebased: Feature/promise based request interceptors #1433

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 154 additions & 54 deletions dist/restangular.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
/**
* Restful Resources service for AngularJS apps
* @version v1.5.2 - 2016-02-08 * @link https://github.com/mgonto/restangular
* @version v1.5.2 - 2016-10-26 * @link https://github.com/mgonto/restangular
* @author Martin Gontovnikas <[email protected]>
* @license MIT License, http://www.opensource.org/licenses/MIT
*/(function() {
*/(function (root, factory) {
// https://github.com/umdjs/umd/blob/master/templates/returnExports.js
if (typeof define === 'function' && define.amd) {
define(['lodash', 'angular'], factory);
} else if (typeof module === 'object' && module.exports) {
module.exports = factory(require('lodash'), require('angular'));
} else {
// No global export, Restangular will register itself as Angular.js module
factory(root._, root.angular);
}
}(this, function (_, angular) {

var restangular = angular.module('restangular', []);

restangular.provider('Restangular', function() {
// Make $q available on callbacks via late variable fullfillment.
var $Q;

// Configuration
var Configurer = {};
Configurer.init = function(object, config) {
Expand Down Expand Up @@ -61,6 +74,15 @@ restangular.provider('Restangular', function() {
return this;
};

/**
* Always return plain data, no restangularized object
**/
config.plainByDefault = config.plainByDefault || false;
object.setPlainByDefault = function(value) {
config.plainByDefault = value === true ? true : false;
return this;
}

config.withHttpValues = function(httpLocalConfig, obj) {
return _.defaults(obj, httpLocalConfig, config.defaultHttpFields);
};
Expand Down Expand Up @@ -188,12 +210,14 @@ restangular.provider('Restangular', function() {
oneUrl: 'oneUrl',
allUrl: 'allUrl',
customPUT: 'customPUT',
customPATCH: 'customPATCH',
customPOST: 'customPOST',
customDELETE: 'customDELETE',
customGET: 'customGET',
customGETLIST: 'customGETLIST',
customOperation: 'customOperation',
doPUT: 'doPUT',
doPATCH: 'doPATCH',
doPOST: 'doPOST',
doDELETE: 'doDELETE',
doGET: 'doGET',
Expand Down Expand Up @@ -334,10 +358,27 @@ restangular.provider('Restangular', function() {
config.fullRequestInterceptor = function(element, operation, path, url, headers, params, httpConfig) {
var interceptors = angular.copy(config.requestInterceptors);
var defaultRequest = config.defaultInterceptor(element, operation, path, url, headers, params, httpConfig);
return _.reduce(interceptors, function(request, interceptor) {
return _.extend(request, interceptor(request.element, operation,
path, url, request.headers, request.params, request.httpConfig));
}, defaultRequest);
var promise = $Q.when(defaultRequest);

_.forEach(interceptors, function (interceptor) {
promise = promise.then(function (request) {
var args = [
request.element,
operation,
path,
url,
request.headers,
request.params,
request.httpConfig
];

return $Q.when(interceptor.apply(window, args)).then(function (req) {
return _.extend(request, req);
});
});
});

return promise;
};

object.addRequestInterceptor = function(interceptor) {
Expand Down Expand Up @@ -641,7 +682,7 @@ restangular.provider('Restangular', function() {
Path.prototype = new BaseCreator();

Path.prototype.normalizeUrl = function (url){
var parts = /(http[s]?:\/\/)?(.*)?/.exec(url);
var parts = /((?:http[s]?:)?\/\/)?(.*)?/.exec(url);
parts[2] = parts[2].replace(/[\\\/]+/g, '/');
return (typeof parts[1] !== 'undefined')? parts[1] + parts[2] : parts[2];
};
Expand Down Expand Up @@ -759,6 +800,8 @@ restangular.provider('Restangular', function() {


this.$get = ['$http', '$q', function($http, $q) {
// Fullfill $Q.
$Q = $q;

function createServiceForConfiguration(config) {
var service = {};
Expand Down Expand Up @@ -927,20 +970,16 @@ restangular.provider('Restangular', function() {

function addCustomOperation(elem) {
elem[config.restangularFields.customOperation] = _.bind(customFunction, elem);
_.each(['put', 'post', 'get', 'delete'], function(oper) {
var requestMethods = { get: customFunction, delete: customFunction };
_.each(['put', 'patch', 'post'], function(name) {
requestMethods[name] = function(operation, elem, path, params, headers) {
return _.bind(customFunction, this)(operation, path, params, headers, elem);
};
});
_.each(requestMethods, function(requestFunc, name) {
var callOperation = name === 'delete' ? 'remove' : name;
_.each(['do', 'custom'], function(alias) {
var callOperation = oper === 'delete' ? 'remove' : oper;
var name = alias + oper.toUpperCase();
var callFunction;

if (callOperation !== 'put' && callOperation !== 'post') {
callFunction = customFunction;
} else {
callFunction = function(operation, elem, path, params, headers) {
return _.bind(customFunction, this)(operation, path, params, headers, elem);
};
}
elem[name] = _.bind(callFunction, elem, callOperation);
elem[alias + name.toUpperCase()] = _.bind(requestFunc, elem, callOperation);
});
});
elem[config.restangularFields.customGETLIST] = _.bind(fetchFunction, elem);
Expand Down Expand Up @@ -1006,7 +1045,9 @@ restangular.provider('Restangular', function() {
function restangularizeCollectionAndElements(parent, element, route) {
var collection = restangularizeCollection(parent, element, route, false);
_.each(collection, function(elem) {
restangularizeElem(parent, elem, route, false);
if (elem) {
restangularizeElem(parent, elem, route, false);
}
});
return collection;
}
Expand Down Expand Up @@ -1050,9 +1091,6 @@ restangular.provider('Restangular', function() {
var url = urlHandler.fetchUrl(this, what);
var whatFetched = what || __this[config.restangularFields.route];

var request = config.fullRequestInterceptor(null, operation,
whatFetched, url, headers || {}, reqParams || {}, this[config.restangularFields.httpConfig] || {});

var filledArray = [];
filledArray = config.transformElem(filledArray, true, whatFetched, service);

Expand All @@ -1062,7 +1100,10 @@ restangular.provider('Restangular', function() {
method = 'jsonp';
}

var okCallback = function(response) {
/**
* Called upon response success.
*/
function okCallback(response) {
var resData = response.data;
var fullParams = response.config.params;
var data = parseResponse(resData, operation, whatFetched, url, response, deferred);
Expand All @@ -1074,6 +1115,11 @@ restangular.provider('Restangular', function() {
if (!_.isArray(data)) {
throw new Error('Response for getList SHOULD be an array and not an object or something else');
}

if (true === config.plainByDefault) {
return resolvePromise(deferred, response, data, filledArray);
}

var processedData = _.map(data, function(elem) {
if (!__this[config.restangularFields.restangularCollection]) {
return restangularizeElem(__this, elem, what, true, data);
Expand Down Expand Up @@ -1112,17 +1158,45 @@ restangular.provider('Restangular', function() {
filledArray
);
}
};
}

urlHandler.resource(this, $http, request.httpConfig, request.headers, request.params, what,
this[config.restangularFields.etag], operation)[method]().then(okCallback, function error(response) {
/**
* Called upon response or interception error.
*/
function errorCallback(response) {
if (response.status === 304 && __this[config.restangularFields.restangularCollection]) {
resolvePromise(deferred, response, __this, filledArray);
} else if ( _.every(config.errorInterceptors, function(cb) { return cb(response, deferred, okCallback) !== false; }) ) {
// triggered if no callback returns false
deferred.reject(response);
}
});
}

/**
* Called with resolved request from interceptors.
*/
function makeRequest(request) {
urlHandler.resource.apply(urlHandler, [
__this,
$http,
request.httpConfig,
request.headers,
request.params,
what,
__this[config.restangularFields.etag],
operation
])[method]().then(okCallback, errorCallback);
}

config.fullRequestInterceptor.apply(config, [
null,
operation,
whatFetched,
url,
headers || {},
reqParams || {},
this[config.restangularFields.httpConfig] || {}
]).then(makeRequest, errorCallback);

return restangularizePromise(deferred.promise, true, filledArray);
}
Expand Down Expand Up @@ -1154,18 +1228,25 @@ restangular.provider('Restangular', function() {
if (_.isObject(callObj) && config.isRestangularized(callObj)) {
callObj = stripRestangular(callObj);
}
var request = config.fullRequestInterceptor(callObj, operation, route, fetchUrl,
headers || {}, resParams || {}, this[config.restangularFields.httpConfig] || {});

var filledObject = {};
filledObject = config.transformElem(filledObject, false, route, service);

var okCallback = function(response) {
/**
* Called upon response success.
*/
function okCallback(response) {
var resData = response.data;
var fullParams = response.config.params;
var elem = parseResponse(resData, operation, route, fetchUrl, response, deferred);

if (elem) {
var data;

if (true === config.plainByDefault) {
return resolvePromise(deferred, response, elem, filledObject);
}

if (operation === 'post' && !__this[config.restangularFields.restangularCollection]) {
data = restangularizeElem(
__this[config.restangularFields.parentResource],
Expand Down Expand Up @@ -1193,40 +1274,59 @@ restangular.provider('Restangular', function() {
} else {
resolvePromise(deferred, response, undefined, filledObject);
}
};
}

var errorCallback = function(response) {
/**
* Called upon response or interception error.
*/
function errorCallback(response) {
if (response.status === 304 && config.isSafe(operation)) {
resolvePromise(deferred, response, __this, filledObject);
} else if ( _.every(config.errorInterceptors, function(cb) { return cb(response, deferred, okCallback) !== false; }) ) {
// triggered if no callback returns false
deferred.reject(response);
}
};
// Overriding HTTP Method
var callOperation = operation;
var callHeaders = _.extend({}, request.headers);
var isOverrideOperation = config.isOverridenMethod(operation);
if (isOverrideOperation) {
callOperation = 'post';
callHeaders = _.extend(callHeaders, {'X-HTTP-Method-Override': operation === 'remove' ? 'DELETE' : operation.toUpperCase()});
} else if (config.jsonp && callOperation === 'get') {
callOperation = 'jsonp';
}

if (config.isSafe(operation)) {
/**
* Called with resolved request from interceptors.
*/
function makeRequest(request) {
// Overring HTTP Method
var callOperation = operation;
var callHeaders = _.extend({}, request.headers);
var isOverrideOperation = config.isOverridenMethod(operation);
if (isOverrideOperation) {
urlHandler.resource(this, $http, request.httpConfig, callHeaders, request.params,
what, etag, callOperation)[callOperation]({}).then(okCallback, errorCallback);
callOperation = 'post';
callHeaders = _.extend(callHeaders, {'X-HTTP-Method-Override': operation === 'remove' ? 'DELETE' : operation.toUpperCase()});
} else if (config.jsonp && callOperation === 'get') {
callOperation = 'jsonp';
}

if (config.isSafe(operation)) {
if (isOverrideOperation) {
urlHandler.resource(__this, $http, request.httpConfig, callHeaders, request.params,
what, etag, callOperation)[callOperation]({}).then(okCallback, errorCallback);
} else {
urlHandler.resource(__this, $http, request.httpConfig, callHeaders, request.params,
what, etag, callOperation)[callOperation]().then(okCallback, errorCallback);
}
} else {
urlHandler.resource(this, $http, request.httpConfig, callHeaders, request.params,
what, etag, callOperation)[callOperation]().then(okCallback, errorCallback);
urlHandler.resource(__this, $http, request.httpConfig, callHeaders, request.params,
what, etag, callOperation)[callOperation](request.element).then(okCallback, errorCallback);
}
} else {
urlHandler.resource(this, $http, request.httpConfig, callHeaders, request.params,
what, etag, callOperation)[callOperation](request.element).then(okCallback, errorCallback);
}

config.fullRequestInterceptor.apply(window, [
callObj,
operation,
route,
fetchUrl,
headers || {},
resParams || {},
this[config.restangularFields.httpConfig] || {}
]).then(makeRequest, errorCallback);

return restangularizePromise(deferred.promise, false, filledObject);
}

Expand Down Expand Up @@ -1351,5 +1451,5 @@ restangular.provider('Restangular', function() {
return createServiceForConfiguration(globalConfiguration);
}];
});

})();
return restangular.name;
}));
Loading