Skip to content

Instantly share code, notes, and snippets.

@gabecoyne
Last active May 26, 2023 03:18
Show Gist options
  • Save gabecoyne/da8d23d5c31be2d5aacbe6ed5b78ebd8 to your computer and use it in GitHub Desktop.
Save gabecoyne/da8d23d5c31be2d5aacbe6ed5b78ebd8 to your computer and use it in GitHub Desktop.
ActiveResource.js
/**
* @providesModule ActiveResource
**/
'use strict';
var _ = require('underscore');
export default class ActiveResource {
static remote : object; // Remote
static base_route : string; // /api/v1/resource
// create instance - new AR(resource)
constructor(resource: object){
this.attributes = resource;
// create attribute if not defined
_.each(resource, (v,k) => { if( !this[k] ) this[k] = v; })
}
attr(key){
return this.attributes[key];
}
static all(callback?:() => [ActiveResource], params = {}){
this.remote.get(this.base_route, params, (resources) => {
if(callback) callback(_.map(resources, (resource) => { return new this(resource) }));
});
}
static find(id, callback?:() => ActiveResource, params = {}){
this.remote.get(this.base_route+"/"+id, params, (resource) => {
if(callback) callback(new this(resource))
});
}
static create(params, callback?:() => ActiveResource){
// TODO: update local instance
this.remote.post(this.base_route, params, (resource) => {
if(callback) callback(new this(resource))
});
}
// params must include id
static update(params, callback?:() => ActiveResource){
if(!params.id) return;
// TODO: update local instance
this.remote.put(this.base_route+"/"+id, params, (resource) => {
if(callback) callback(new this(resource))
});
}
static save(callback?:() => ActiveResource){
this.remote.put(this.base_route+"/"+this.attributes.id, this.attributes, (resource) => {
if(callback && resource && resource.id) callback(new this(resource));
});
}
static destroy(id, callback){
this.remote.del(this.base_route+"/"+id, {}, (result) => {
if(callback) callback(result);
});
}
// wrap response collection as instance objects
// resources/action.json
// we expect this to be some scope that returns a collection of resouces
static get(endpoint, params, callback){
this.remote.get(this.base_route+endpoint, params, (resources) => {
if(callback) callback(_.map(resources, (resource) => { return new this(resource) }));
});
}
// don't wrap response in new instances
static get_json(endpoint, params, callback){
this.remote.get(this.base_route+endpoint, params, callback)
}
reload(callback){
this.constructor.find(this.id, (resource) => {
_.extend(this.attributes, resource.attributes);
_.each(resource.attributes, (v,k) => { if(!_.isFunction(this[k])) this[k] = v; });
if(callback) callback(this);
})
}
set(key, val){
this.attributes[key] = val;
if(!_.isFunction(this[key])) this[key] = val;
}
// we don't expect this to be this instance type
// /resources/:id/action.js
get(endpoint, params, callback){
this.constructor.remote.get(this.constructor.base_route+endpoint, params, callback);
}
}
import RemoteService from 'RemoteService';
import ActiveResource from 'ActiveResource';
var MyService = new RemoteService("https://myservice.com", { api_key: 'top-secret' });
export default class MyResource extends ActiveResource {
static remote = MyService;
static base_route = '/api/v1/my_resources';
// attribute getter overrides
// zero pad all ids
get id(){
return _.lpad(this.attributes.id, 8, '0');
}
}
MyResource.all((resource) => {
console.log(resource.id); // zero padded ids
})
// crud api with attr getter overrides
var my_resource = MyResource.create({ title: 'new' });
var my_resource = MyResource.find(my_resource.id);
my_resource.update({title: 'test'});
my_resource.set('title', 'test2');
my_resource.save();
my_resource.destroy();
/**
* @providesModule RemoteService
**/
'use strict';
const _ = require('underscore');
const SuperAgent = require('superagent');
/**
* Usage:
* var MyService = new RemoteService("https://myservice.com/api/v1", {
* default_param: value
* });
*/
export default class RemoteService {
constructor(host:string, default_params:object){
this.host = host;
this.default_params = default_params;
}
endpoint(path, host) {
return this.host+path;
};
url(path){
var u = this.host+path+"?"+this.obj_to_query(this.params())
return u;
};
obj_to_query(obj, key){
return _.map(obj,(v,k) => {
if (_.isObject(v)) return this.obj_to_query(v, k);
if (key){
return key + '[' + k + ']=' + encodeURIComponent(v);
} else {
return k + '=' + encodeURIComponent(v);
}
}).join('&');
};
params(values) {
return _.extend({}, this.default_params, values);
};
this.get = async function(endpoint, params, success, error, host) {
params = this.params(params);
var uri = this.endpoint(endpoint, host);
// Handle nested params
_.each(params, (val, key) => {
if (typeof(val) === "object"){
_.each(val, (v,k) => { params[key +"["+k+"]"] = v })
delete params[key];
}
});
SuperAgent.get(uri)
.query(params)
.end((err, res) => {
this.on_response(endpoint, err, res, success, error);
});
};
this.post = async function(endpoint, params, success, error, host) {
params = this.params(params);
var uri = this.endpoint(endpoint, host);
SuperAgent.post(uri)
.set('Content-Type', 'application/json')
.send(JSON.stringify(params))
.end((err, res) => {
this.on_response(endpoint, err, res, success, error);
});
},
this.put = async function(endpoint, params, success, error, host) {
params = this.params(params);
var uri = this.endpoint(endpoint, host);
SuperAgent.put(uri)
.set('Content-Type', 'application/json')
.send(params)
.end((err, res) => {
this.on_response(endpoint, err, res, success, error);
});
};
this.del = async function(endpoint, id, params, success, error, host) {
params = this.params(params);
var uri = this.endpoint(endpoint, host);
SuperAgent.del(`${uri}/${id}`)
.set('Content-Type', 'application/json')
.send(params)
.end((err, res) => {
this.on_response(endpoint, err, res, success, error);
});
};
this.on_response = async function(endpoint, err, res, success, error) {
var json = null;
if(err && error) error(err);
if(res) {
// TODO: check res.code == 200
try {
var cleaned_string = JSONHelper.clean_string(res.text)
json = JSON.parse(cleaned_string);
} catch(e) {
if(error) error(e);
}
if(success) success(json);
}
};
};
module.exports = RemoteService;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment