'use strict';
var _ = require('lodash');
var FieldUtils = require('./field_utils');
var WebLink = require('./web_link');
var HalCuriePrefix = require('./hal_curie_prefix');
var LinkCollection = require('./link_collection');
var Resource = require('./resource');
/**
* Create the HAL extension
*
* @constructor
* @implements {Extension}
* @arg {Array} mediaTypes Media types in addition to `application/hal+json`
* that should be handled by this extensions. This allows for custom media
* types based on HAL to be handled properly.
*
* @classdesc
* Extension for processing
* [HAL](http://tools.ietf.org/html/draft-kelly-json-hal-06) responses.
* By default, the extension will only process links and embedded
* resources in responses if the HTTP response `Content-Type` header
* equals `application/hal+json`. If you have a custom media type that
* extends HAL, you can register it by passing it in the `mediaTypes`
* parameter.
*/
var HalExtension = function(mediaTypes) {
var mediaTypeSet = {
'application/hal+json': true,
'application/vnd.hal+json': true
};
mediaTypes = mediaTypes || [];
for (var i = 0; i < mediaTypes.length; i++) {
mediaTypeSet[mediaTypes[i]] = true;
}
this.mediaTypes = _.keys(mediaTypeSet);
this.applies = function(data, headers) {
var h = headers['content-type'];
if (!h) {
return false;
}
// Handle parameters, e.g. application/hal+json; charset=UTF-8
var type = h.split(';')[0];
return mediaTypeSet[type] !== undefined;
};
this.dataParser = function(data) {
return FieldUtils.extractFields(_.omit(data, function(val, key) {
return key === '_links' || key === '_embedded';
}));
};
this.linkParser = function(data, headers, context) {
if (!_.isObject(data._links)) {
return {};
}
var ret = {};
_.forEach(data._links, function(val, key) {
if (!_.isArray(val)) {
val = [val];
}
var linkArray = [];
_.forEach(val, function(l) {
// Because HAL uses link relations as object keys, we populate
// the rel field on the link manually so the link is self
// contained from this point onward.
l.rel = key;
linkArray.push(new WebLink(l, context));
}, this);
ret[key] = LinkCollection.fromArray(linkArray);
}, this);
return ret;
};
this.curiePrefixParser = function(data, headers, context) {
var curies = this.linkParser(data, headers, context).curies;
if (!curies) {
return {};
}
return _(curies).map(function(c) {
return new HalCuriePrefix(c);
}).indexBy('prefix').value();
};
this.embeddedParser = function(data, headers, context, parent) {
var ret = {};
_.forEach(data._embedded || {}, function(val, key) {
if (!_.isArray(val)) {
val = [val];
}
ret[key] = Resource.embeddedCollection(val, headers, context, parent);
});
return ret;
};
};
module.exports = HalExtension;