Created
October 7, 2012 19:38
-
-
Save nikolajbaer/3849339 to your computer and use it in GitHub Desktop.
API adapter for tastypie API
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
// Integrates to Web Cube Enterprise 4.2.4 API | |
var API = function(api_base){ | |
var _api_base = api_base; | |
var _api = this; | |
/* utility function for ajax json request */ | |
var make_request = function(args,api_resource_path,ajax_callback,method,data){ | |
var parameters = ""; | |
if(method == undefined){ method="GET"; } | |
for(var k in args){ | |
if(parameters==""){ | |
parameters+="?"; | |
}else{ | |
parameters += "&"; | |
} | |
parameters += k+"="+encodeURI(args[k]); | |
} | |
var settings={ | |
url:api_resource_path + parameters, | |
success: ajax_callback, | |
dataType: "json", | |
contentType: "application/json" , | |
type: method, | |
}; | |
if(data != undefined){ settings.data = data; } | |
$.ajax(settings); | |
} | |
var BaseObject = { | |
_init: function(model) { | |
this._model = model; | |
this._original = {}; | |
if(model._schema == undefined){ | |
// bail if we are a lightweight reference model | |
// TODO ideal world we figure out what this reference model's schema is, and laod it into the api? | |
// .. but then we would need to do a lookup for all empty models, and back-init all the ones that we | |
// are getting before the schema loads. ugh. | |
return; | |
} | |
// TODO turn each reference field into a Query object | |
for(var f in model._schema.fields){ | |
var field = model._schema.fields[f]; | |
// save original | |
this._original[f] = this[f]; | |
if(field.type=="related"){ | |
// HACK no way to know if this is a many or a single related resource | |
if(field.help_text.substr(0,4) == "Many"){ | |
for(var i=0;i<this[f].length;i++){ | |
if(typeof this[f][i] == "string"){ // it is related resource_uri, so make it a Query | |
console.log(this[f][i]); | |
this[f][i] = new RelatedModel(this[f][i]); | |
}else{ | |
//this[f][i] = $.extend(BaseObject,this[f][i]); // init it, but not with RelatedModel? | |
}// otherwise this was prefetched, so let it be (but maybe we should init it?) | |
} | |
//this[f] = Query(this[f]); // would need to have query that takes in an array of resource_uris | |
}else{ | |
if(typeof this[f] == "string"){ // it is related resource_uri, so make it a Query | |
this[f] = new RelatedModel(this[f]); | |
} | |
} | |
} | |
} | |
}, | |
do_action:function(action,data,callback){ | |
// TODO | |
if( this._model._schema.actions == undefined || | |
this._model_schema.actions[action] == undefined){ throw "No such action available"; } | |
make_request({},this.resource_uri+action,callback,"POST",JSON.stringify(data)); | |
}, | |
save:function(){ | |
if(this._model == undefined){ throw "Object does not have a _model"; } | |
// TODO if this model has a _resource_uri, PUT there | |
// Foreach field, check if it has changed based upon the _original | |
// - If related field, check if that has changed based upon the _original | |
// Create PUT and execute | |
// - Then create PUT and execute for all RelatedModels | |
// TODO check how Django Admin does this process? | |
}, | |
delete:function(){ | |
// TODO handle | |
// NOTE: maybe don't add this if we are read-only? or just throw exception? | |
} | |
} | |
var RelatedModel = function(related_resource_uri){ | |
this.resource_uri = related_resource_uri; | |
this.get_resource_uri = function(){ | |
return this.resource_uri; | |
} | |
this.get = function(callback,options){ | |
var q = new Query(this,callback,options); | |
q.fetch(); | |
return q; | |
} | |
} | |
var BaseModel = { | |
get: function(callback,args,options){ | |
// TODO make this chain-able? | |
default_args = { | |
limit: 20, | |
offset: 0 | |
} | |
default_options = { | |
page_progress_callback: null // called as each page is loaded with current progress | |
} | |
var opt = $.extend(default_options,options); | |
opt.args = $.extend(default_args,args); | |
var q = new Query(this,callback,options); | |
// shoudl this be done automatically? | |
q.fetch(); | |
return q; | |
}, | |
get_resource_uri: function(){ | |
return _api_base + this._resource_path; | |
}, | |
_import_schema: function(){ | |
if(this._schema == undefined){ return; } | |
// TODO build a BaseObject, and extend it based upon the fields? | |
// | |
} | |
} | |
var Query = function(model,final_callback,options){ | |
this.model = model; | |
this.status = "pending"; | |
this.final_callback = final_callback; | |
this.results = []; | |
this.total_count = null; | |
var _query = this; // for closure | |
// handle missing options, options.args | |
if(options == undefined){ options = {args:{}}; } | |
if(options.args == undefined){ options.args = {}; } | |
this.options = options; | |
var query_callback = function(data){ | |
console.log("Got ",data," for query ",_query); | |
// process list or single result | |
var results = null; | |
if(data.meta == undefined){ | |
// fix the query count if we just got one object | |
_query.total_count = 1; | |
var results = [data]; | |
}else{ | |
results = data.objects; | |
_query.total_count = data.meta.total_count; | |
} | |
console.log(results); | |
// process the results | |
for(var i=0;i<results.length;i++){ | |
var obj = $.extend({},BaseObject,results[i]); | |
obj._init(_query.model); | |
console.log(obj); | |
_query.results.push(obj); | |
} | |
console.log(_query.results); | |
// if there are paged results, trigger the next page now | |
if(data.meta != undefined && data.meta.next != null){ | |
make_request(_query.options.args,data.meta.next,query_callback); | |
if(typeof _query.options.page_progress_callback === "function"){ | |
// probably some sort of "progress event" would be best | |
_query.options.page_progress_callback({last_page:data.objects,query:_query}); | |
} | |
} | |
// fire the final callback if we are done, and set the status | |
if(data.meta == undefined || (data.meta != undefined && data.meta.next == null)){ | |
_query.status = "complete"; | |
if(typeof _query.final_callback === 'function'){ | |
_query.final_callback(_query); | |
} | |
} | |
} | |
this.fetch = function(){ | |
make_request(_query.options.args,_query.model.get_resource_uri(),query_callback); | |
} | |
} | |
/* Import | |
* | |
* Imports all the specified resource paths in the style "app/model" (e.g. "blog/blogentry"). Accepts a string or list | |
* If specified, the callback will be called as each is loaded with the resulting Model object as the result | |
* | |
*/ | |
this.import = function(resource_paths,callback){ | |
if(typeof resource_paths == "string"){ | |
resource_paths = [resource_paths]; | |
} | |
for(var r in resource_paths){ | |
var resource_path=resource_paths[r]; | |
make_request({},_api_base + resource_path,function(obj){ | |
var o=_api; | |
var res = resource_path.split("/"); | |
for (var p in res){ | |
if(o[res[p]] == undefined){ | |
o[res[p]]={}; | |
} | |
o=o[res[p]]; | |
} | |
o._resource_path = resource_path; | |
if(obj.meta!=undefined){ | |
// if we have a meta object, then we are at an endpoint | |
// TODO load teh schema.. what do wew want to do then? | |
//make_request(obj[ | |
// Add Object Methods | |
$.extend(o,BaseModel); | |
make_request({},_api_base + resource_path+"/schema",function(obj){ | |
console.log("updating schema for:" + o._resource_path); | |
console.log(obj); | |
o._schema = obj; | |
o._import_schema(); | |
}); | |
}else{ | |
// otherwise treat all items as different endpoints | |
for(var k in obj){ | |
o[k] = {list_endpoint:obj[k].list_endpoint,schema:obj[k].schema}; | |
// Do we populate this schema? | |
} | |
} | |
if(typeof callback === "function"){ | |
callback(o); | |
} | |
}); | |
} | |
} | |
} | |
// debug | |
var api = new API("/api/v1/"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment