web_link.js

'use strict';

var _ = require('lodash');
var Resource = require('./resource');
var UriTemplate = require('URIjs/src/URITemplate');

/**
 * Create a new WebLink.
 * @constructor
 * @arg {Object} data the field values for the link
 * @arg {Context} context The resource context containing the link
 *
 * @classdesc
 * Currently, there is one implementation of the concept of a link,
 * {@link WebLink}, which encapsulates the data and concepts codified in
 * [RFC5988](http://tools.ietf.org/html/rfc5988). The standard data fields (if
 * defined for the specific link), such as `href`, `title`, `type`, etc are all
 * defined on the link.
 */
var WebLink = function(data, context) {
  _.extend(this, data);
  this.$$context = context;
};

/**
 * Dereference the link, returning an asynchronously
 * populated {@link Resource}.
 * @arg {Object} [options] The options for the request.
 * @arg {Object} [options.protocol] Options to pass to the underlying protocol,
 * @arg {Boolean} [options.preferContextMediaType] Whether to prefer the media type
 * that originated this WebLink in the Accept header of the request, e.g.
 * `Accept: application/vnd.collection+json, application/vnd.siren+json;q=0.5`
 * @arg {Object} [options.data] When following a link that is a URI Template,
 * this object will used as variables when resolving the template into the
 * final URI.
 * @tutorial uri-templates
 */
WebLink.prototype.follow = function(options) {
  options = this.$$context.withDefaults(options);
  var opts = _.get(options, 'protocol', {});
  opts.headers = (opts.headers || {});

  if(!opts.headers.Accept) {
    if (this.type) {
      opts.headers.Accept = this.type;
    } else {
      opts.headers.Accept = this.$$context.acceptHeader();
    }
  }

  var requestOptions = _.extend(opts, { url: this.resolvedUrl(_.get(options, 'data')) });
  return Resource.fromRequest(this.$$context.http(requestOptions), this.$$context);
};

/**
 * The `resolvedUrl` function of a `HyRes.WebLink` can be used to see what the final resolved URL will be for the link once processing:
 *
 * * URI Template parameters passed in the `data` argument.
 * * Converting any relative URLs to absolute ones given the context of the web link, i.e. the URL of the response that contained the link.
 * @arg {Object} data The values to optionally insert into any URI template used for the `href` value.
 */
WebLink.prototype.resolvedUrl = function(data) {
  var url = this.href;

  if (this.templated) {
    url = new UriTemplate(url).expand(data);
  }

  return this.$$context.resolveUrl(url);
};

module.exports = WebLink;