UNPKG

5.15 kBJavaScriptView Raw
1'use strict';
2
3var _ = require('lodash');
4var helpers = require('./helpers');
5var responseParser = require('./responseparser');
6var request = require('./request');
7
8// A resource on the API, instances of this are used as the prototype of
9// instances of each API resource. This constructor will build up a method
10// for each action that can be performed on the resource.
11//
12// - @param {Object} options
13// - @param {Object} schema
14//
15// The `options` argument should have the following properties:
16//
17// - `resourceDefinition` - the definition of the resource and its actions from
18// the schema definition.
19// - `consumerkey` - the oauth consumerkey
20// - `consumersecret` the oauth consumersecret
21// - `schema` - the schema defintion
22// - `format` - the desired response format
23// - `logger` - for logging output
24function Resource(options, schema) {
25 this.logger = options.logger;
26 this.resourceName = options.resourceDefinition.resource;
27 this.host = options.resourceDefinition.host || schema.host;
28 this.sslHost = options.resourceDefinition.sslHost || schema.sslHost;
29 this.port = options.resourceDefinition.port || schema.port;
30 this.prefix = options.resourceDefinition.prefix || schema.prefix;
31 this.consumerkey = options.consumerkey;
32 this.consumersecret = options.consumersecret;
33
34 this.logger.silly('Creating constructor for resource: ' +
35 this.resourceName);
36
37 _.each(options.resourceDefinition.actions,
38 function processAction(action) {
39 this.createAction(action, options.userManagement);
40 }, this);
41}
42
43// Figure out the appropriate method name for an action on a resource on
44// the API
45//
46// - @param {Mixed} - actionDefinition - Either a string if the action method
47// name is the same as the action path component on the underlying API call
48// or a hash if they differ.
49// - @return {String}
50Resource.prototype.chooseMethodName = function (actionDefinition) {
51 var fnName;
52
53 // Default the action name to getXXX if we only have the URL slug as the
54 // action definition.
55 if (_.isString(actionDefinition)) {
56 fnName = 'get' + helpers.capitalize(actionDefinition);
57 } else {
58 fnName = actionDefinition.methodName;
59 }
60
61 return fnName;
62};
63
64// Utility method for creating the necessary methods on the Resource for
65// dispatching the request to the 7digital API.
66//
67// - @param {Mixed} actionDefinition - Either a string if the action method
68// name is the same as the action path component on the underlying API call
69// or a hash if they differ.
70Resource.prototype.createAction = function (actionDefinition, isManaged) {
71 var url;
72 var fnName = this.chooseMethodName(actionDefinition);
73 var action = typeof actionDefinition.apiCall === 'undefined' ?
74 actionDefinition : actionDefinition.apiCall;
75 var httpMethod = (actionDefinition.method || 'GET').toUpperCase();
76 var host = actionDefinition.host || this.host;
77 var sslHost = actionDefinition.sslHost || this.sslHost;
78 var port = actionDefinition.port || this.port;
79 var prefix = actionDefinition.prefix || this.prefix;
80 var authType = (actionDefinition.oauth
81 && actionDefinition.oauth === '3-legged' && isManaged)
82 ? '2-legged'
83 : actionDefinition.oauth;
84
85 this.logger.silly('Creating method: ' + fnName + ' for ' + action +
86 ' action with ' + httpMethod + ' HTTP verb');
87 /*jshint validthis: true */
88 function invokeAction(requestData, callback) {
89 var self = this;
90 var endpointInfo = {
91 host: invokeAction.host,
92 sslHost: invokeAction.sslHost || sslHost,
93 port: invokeAction.port,
94 prefix: invokeAction.prefix,
95 authtype: authType,
96 url: helpers.formatPath(invokeAction.prefix, this.resourceName,
97 action)
98 };
99 var credentials = {
100 consumerkey: this.consumerkey,
101 consumersecret: this.consumersecret
102 };
103
104 if (_.isFunction(requestData)) {
105 callback = requestData;
106 requestData = {};
107 }
108
109 function checkAndParse(err, data, response) {
110 if (err) {
111 return callback(err);
112 }
113
114 return responseParser.parse(data, {
115 format: self.format,
116 logger: self.logger,
117 url: endpointInfo.url,
118 params: requestData,
119 contentType: response.headers['content-type']
120 }, getLocationForRedirectsAndCallback);
121 function getLocationForRedirectsAndCallback(err, parsed) {
122 if (err) {
123 return callback(err);
124 }
125
126 if (response && response.headers['location']) {
127 parsed.location = response.headers['location'];
128 }
129
130 return callback(null, parsed);
131 }
132 }
133
134 _.defaults(requestData, this.defaultParams);
135
136 if (httpMethod === 'GET') {
137 // Add the default parameters to the request data
138 return request.get(endpointInfo, requestData, this.headers,
139 credentials, this.logger, checkAndParse);
140 }
141
142 if (httpMethod === 'POST' || httpMethod === 'PUT') {
143 return request.postOrPut(httpMethod, endpointInfo, requestData,
144 this.headers, credentials, this.logger, checkAndParse);
145 }
146
147 return callback(new Error('Unsupported HTTP verb: ' + httpMethod));
148 }
149
150 invokeAction.action = action;
151 invokeAction.authtype = authType;
152 invokeAction.host = host;
153 invokeAction.sslHost = sslHost;
154 invokeAction.port = port;
155 invokeAction.prefix = prefix;
156 this[fnName] = invokeAction;
157};
158
159module.exports = Resource;