Skip to content

Instantly share code, notes, and snippets.

@jarib
Last active August 29, 2015 14:01
Show Gist options
  • Save jarib/9f55538c019824bfd9aa to your computer and use it in GitHub Desktop.
Save jarib/9f55538c019824bfd9aa to your computer and use it in GitHub Desktop.
Prototyping a simple json+hal client
node_modules
var Promise = require('bluebird');
var halfred = require('halfred');
var parseTemplate = require('uri-template').parse;
var request = Promise.promisify(require('request'));
halfred.enableValidation();
function Builder(parent) {
this.parent = parent;
this.rels = [];
}
Builder.fake = false;
Builder.fakeResponses = {
"http://api.io/": {
_links: {"ea:orders": {href: "http://api.io/orders"}}
},
"http://api.io/orders": {
_links: {"ea:find": {href: "http://api.io/orders/{id}", templated: true}}
},
"http://api.io/orders/13": {
_links: {
"ea:customer": {href: "http://api.io/customer/42"},
"ea:basket": {href: "http://api.io/basket/123"}
}
},
"http://api.io/customer/42": {
name: 'customer 42'
},
"http://api.io/basket/123": {
name: 'basket 123'
}
}
Builder.prototype.href = function (url) {
this.rels.push({href: url});
return new Builder(this);
}
Builder.prototype.follow = function (rel, params) {
this.rels.push({rel: rel, params: params || {}});
return new Builder(this);
}
Builder.prototype.dump = function () {
if (this.parent) {
this.parent.dump();
}
console.log(JSON.stringify(this, null, ' '));
}
Builder.prototype.get = function () {
var self = this;
function fetchRels() {
return Promise.all(
self.rels.map(self._fetchRelation.bind(self))
).then(function () {
return self._merge();
});
}
if (self.parent) {
return self.parent.get().then(fetchRels);
} else {
return fetchRels();
}
}
Builder.prototype._fetchRelation = function (rel) {
var href;
if (rel.rel) {
var link;
this.parent.rels.some(function (r) {
// TODO: handle array relations
link = r.resource.link(rel.rel);
return link;
})
if (!link) {
throw new Error(
"no link relation for " + rel.rel + " in " + JSON.stringify(this.parent.rels));
}
if (link.templated) {
href = parseTemplate(link.href).expand(rel.params);
} else {
href = link.href;
}
} else if (rel.href) {
var href = rel.href;
}
return this._fetch(href).then(function (resource) {
rel.resource = resource;
});
}
Builder.prototype._merge = function (childData) {
var resp = {};
this.rels.forEach(function (rel) {
if (rel.rel) {
resp[rel.rel] = rel.resource.original();
}
});
if (childData) {
Object.keys(childData).forEach(function (key) {
resp[key] = childData[key];
})
};
if (this.parent) {
resp = this.parent._merge(resp);
}
return resp;
}
Builder.prototype._fetch = function (url) {
console.log("fetching url", url);
if (Builder.fake) {
return Promise.resolve(halfred.parse(Builder.fakeResponses[url]));
} else {
return request({
method: 'GET',
url: url,
headers: {
'User-Agent': 'hal-sugar @ https://gist.github.com/9f55538c019824bfd9aa',
'Accept': 'application/hal+json'
}
}).spread(function (response, body) {
// TODO: error handling
console.log("got response", response.statusCode);
return halfred.parse(JSON.parse(body));
});
}
}
var api;
if (Builder.fake) {
api = new Builder().href('http://api.io/')
var order = api.follow("ea:orders").follow("ea:find", {id: 13})
order.follow('ea:basket')
order.follow('ea:customer')
order.get().then(function (res) {
console.log(JSON.stringify(res, null, ' '));
})
} else {
api = new Builder().href('http://www.holderdeord.no/api/')
var representative = api.follow('representatives').follow('find', {slug: 'es'});
representative.follow('party')
representative.follow('committees')
representative.get().then(function (res) {
console.log(JSON.stringify(Object.keys(res), null, ' '));
});
}
{
"dependencies": {
"request": "~2.36.0",
"bluebird": "~1.2.4",
"halfred": "~0.2.0",
"uri-template": "~0.4.1"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment