In every authenticated requests (GET, POST, etc) of my Backbone/Marionette application I must to attach an accessToken.
I store this accessToken and expireDate in the localStorage.
To check if the accessToken is expired I call this method: user.checkToken(). If is expired, the method renew the accessToken with a POST request to my backend.
Where should I put this check? I mean, in which part of the application?
Should I rewrite my on Backbone.sync method or use ajax.setup "beforeSend" ?
Thanks in advance for your advices/idea.
Backbone uses jQuery (see the note for a solution that may work with Zepto) for ajax requests, so you can use (as suggested by Edward) jQuery.ajaxPrefilter.
I did a little test for this task, let me know if there's any problem:
function tokenIsExpired() {
return true;
}
function createPromiseFunction(method, jqXHRsource, jqXHR) {
return function() {
jqXHRsource[method] = function(f) {
if (f) {
jqXHR[method] = function() {
f.apply(this, arguments);
};
}
return this;
};
}
}
function updateToken() {
return $.ajax({
url: '',
method: 'GET',
data: {some:'data', here:'yes'},
success: function() {
// update the token sir
console.log('token call done')
},
skipTokenCheck: true // required
});
}
$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
/*
* check if token is expired every time a new ajax request is made
* if it is expired, aborts the current requests, updated the token
* and eventually does the original request again.
*/
if (!options.skipTokenCheck && tokenIsExpired()) {
// at this point no callback should have be added to the promise object
var methodsNames = [
'done',
'always',
'fail',
'progress',
'then'
];
var methods = {};
// copy the callbacks when they're added to the old request
for (var i = 0; i < methodsNames.length; i++) {
var name = methodsNames[i];
createPromiseFunction(name, jqXHR, methods)();
};
jqXHR.abort();
// TODO: error checks
updateToken().done(function() {
console.log('done');
var newReq = $.ajax($.extend(originalOptions, {skipTokenCheck: true}));
for (var i = 0; i < methodsNames.length; i++) {
var name = methodsNames[i];
var f = methods[name];
if (f) {
newReq[name](f);
}
};
});
}
});
var p = $.get('.');
p.done(function() { console.log(arguments); }).fail(function() {
console.log('fail');
});
Looks like that ajaxPrefilter doesn't work with Zepto. Alternatively you can use the ajaxBeforeSend event.
Returning false in the beforeSend function will cancel the request.
Should be easy to adapt the code I posted above.