rest-boubou
Version:
RESTful HTTP client library
140 lines (123 loc) • 4.48 kB
JavaScript
/*
* Copyright 2013-2015 the original author or authors
* @license MIT, see LICENSE.txt for details
*
* @author Scott Andrews
*/
(function (define) {
'use strict';
define(function (require) {
var pathPrefix, template, find, lazyPromise, responsePromise, when;
pathPrefix = require('../../../interceptor/pathPrefix');
template = require('../../../interceptor/template');
find = require('../../../util/find');
lazyPromise = require('../../../util/lazyPromise');
responsePromise = require('../../../util/responsePromise');
when = require('when');
function defineProperty(obj, name, value) {
Object.defineProperty(obj, name, {
value: value,
configurable: true,
enumerable: false,
writeable: true
});
}
/**
* Hypertext Application Language serializer
*
* Implemented to https://tools.ietf.org/html/draft-kelly-json-hal-06
*
* As the spec is still a draft, this implementation will be updated as the
* spec evolves
*
* Objects are read as HAL indexing links and embedded objects on to the
* resource. Objects are written as plain JSON.
*
* Embedded relationships are indexed onto the resource by the relationship
* as a promise for the related resource.
*
* Links are indexed onto the resource as a lazy promise that will GET the
* resource when a handler is first registered on the promise.
*
* A `requestFor` method is added to the entity to make a request for the
* relationship.
*
* A `clientFor` method is added to the entity to get a full Client for a
* relationship.
*
* The `_links` and `_embedded` properties on the resource are made
* non-enumerable.
*/
return {
read: function (str, opts) {
var client, console;
opts = opts || {};
client = opts.client;
console = opts.console || console;
function deprecationWarning(relationship, deprecation) {
if (deprecation && console && console.warn || console.log) {
(console.warn || console.log).call(console, 'Relationship \'' + relationship + '\' is deprecated, see ' + deprecation);
}
}
return opts.registry.lookup(opts.mime.suffix).then(function (converter) {
return when(converter.read(str, opts)).then(function (root) {
find.findProperties(root, '_embedded', function (embedded, resource, name) {
Object.keys(embedded).forEach(function (relationship) {
if (relationship in resource) { return; }
var related = responsePromise({
entity: embedded[relationship]
});
defineProperty(resource, relationship, related);
});
defineProperty(resource, name, embedded);
});
find.findProperties(root, '_links', function (links, resource, name) {
Object.keys(links).forEach(function (relationship) {
var link = links[relationship];
if (relationship in resource) { return; }
defineProperty(resource, relationship, responsePromise.make(lazyPromise(function () {
if (link.deprecation) { deprecationWarning(relationship, link.deprecation); }
if (link.templated === true) {
return template(client)({ path: link.href });
}
return client({ path: link.href });
})));
});
defineProperty(resource, name, links);
defineProperty(resource, 'clientFor', function (relationship, clientOverride) {
var link = links[relationship];
if (!link) {
throw new Error('Unknown relationship: ' + relationship);
}
if (link.deprecation) { deprecationWarning(relationship, link.deprecation); }
if (link.templated === true) {
return template(
clientOverride || client,
{ template: link.href }
);
}
return pathPrefix(
clientOverride || client,
{ prefix: link.href }
);
});
defineProperty(resource, 'requestFor', function (relationship, request, clientOverride) {
var client = this.clientFor(relationship, clientOverride);
return client(request);
});
});
return root;
});
});
},
write: function (obj, opts) {
return opts.registry.lookup(opts.mime.suffix).then(function (converter) {
return converter.write(obj, opts);
});
}
};
});
}(
typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }
// Boilerplate for AMD and Node
));