src/util/NorthAmpliaREST.js
'use strict';
import merge from 'merge';
import urlencode from 'urlencode';
import request from 'superagent';
import q from 'q';
import _ from 'lodash'
import mime from 'mime-types'
// MOCK user searching
import _mock from 'superagent-mocker';
const mock = _mock(request);
//
/**
* This is a wrapper of a Rest api javascript
*/
export default class NorthAmpliaREST {
/**
* This is a constructor of a Rest api javascript
* @param {{ url: string,port: string,version: string,apiKey: string,JTW: string}} _options - this is configuration about Opengate North API.
* @param {function} backend - this is a backend selected to manage a request to Opengate North API.
*/
constructor(_options, headers) {
this._options = merge.recursive(true, this.default(), _options);
this._headers = headers;
if (!_.isEmpty(_options.mocks)) {
this._applyMocks(_options.mocks)
}
// ---------------------------------- EXAMPLE
/*
mock.post(_options.url + '/north/v80/search/channels', function(req) {
return {
body: {
"channels": [{
"name": "default_channel",
"description": "Automatic channel",
"organization": "organization_GetSetParam",
"certificates": []
}]
},
statusCode: 200
};
});
*/
// mock.post(_options.url + '/north/v80/provision/organizations/:organization/software', function(req) {
// return {
// body: {
// "software": []
// },
// statusCode: 201
// };
// });
// mock.put(_options.url + '/north/v80/provision/organizations/:organization/software/:id', function(req) {
// return {
// body: {
// "software": []
// },
// statusCode: 200
// };
// });
// mock.del(_options.url + '/north/v80/provision//organizations/:organization/software/:id', function(req) {
// return {
// body: {
// "software": []
// },
// statusCode: 200
// };
// });
// mock.get(_options.url + '/north/v80/provision//organizations/:organization/software?visibility=administrable', function(req) {
// return {
// body: {
// "software": [{
// "id": "00000-11111-22222-33333",
// "name": "software name 1",
// "type": "SOFTWARE",
// "version": "0.000001",
// "organization": req.params.organization,
// "models": []
// },
// {
// "id": "00000-11111-22222-44444",
// "name": "software name 2",
// "type": "FIRMWARE",
// "version": "0.000002",
// "organization": req.params.organization,
// "models": []
// }]
// },
// statusCode: 200
// };
// });
}
_applyMocks(mocks) {
const methods = Object.keys(mocks).filter((method) => !_.isEmpty(mocks[method]))
methods.forEach(method => {
console.log(`Mocking ${method.toLocaleUpperCase()} requests`);
Object.keys(mocks[method]).forEach(url => {
console.log('Mocking url:', url);
const methodByUrl = mocks[method][url]
mock[method](this._options.url + url, (req) => {
if (typeof methodByUrl === 'function') {
console.log('Function returned')
return methodByUrl(req)
} else {
const data = mocks[method][url]
console.log('Data returned:', data)
if (!data.headers) data.headers = {}
return data
}
});
})
})
}
/**
* This return a default configuration object
* @return {object}
*/
default() {
return {
timeout: 5000
};
}
_url(options) {
return options.url;
}
/**
* Invoke GET action to url specified
* @param {!string} url - url to execute GET
* @param {number} timeout - timeout in milliseconds
* @param {object} headers - headers of request
* @param {object} parameters - parameters of request
* @param {boolean} asBlob - response body as Blob
* @param {string} serviceBaseURL - base of the uri petition
* @return {Promise}
*/
get(url, timeout, headers, parameters, asBlob, serviceBaseURL) {
const _url = this._createUrl(url, parameters, serviceBaseURL)
console.info('GET', _url)
var req = request.get(_url);
return this._createPromiseRequest(req, null, timeout, headers, asBlob);
}
/**
* Invoke PATCH action to url and data specified
* @param {!string} url - url to execute PATCH
* @param {object} data - attach data to request PATCH
* @param {number} timeout - timeout in milliseconds
* @param {object} headers - headers of request
* @param {object} parameters - parameters of request
* @param {string} serviceBaseURL - base of the uri petition
* @return {Promise}
*/
patch(url, data, timeout, headers, parameters, serviceBaseURL) {
const _url = this._createUrl(url, parameters, serviceBaseURL)
console.info('PATCH', _url)
var req = request.patch(_url)
.send(data);
return this._createPromiseRequest(req, null, timeout, headers);
}
/**
* Invoke POST action to url and data specified
* @param {!string} url - url to execute POST
* @param {object} data - attach data to request POST
* @param {number} timeout - timeout in milliseconds
* @param {object} headers - headers of request
* @param {object} parameters - parameters of request
* @param {string} serviceBaseURL - base of the uri petition
* @return {Promise}
*/
post(url, data, timeout, headers, parameters, serviceBaseURL) {
const _url = this._createUrl(url, parameters, serviceBaseURL)
console.info('POST', _url)
var req = request.post(_url)
.send(data);
return this._createPromiseRequest(req, null, timeout, headers);
}
/**
* Invoke POST multipart action to url and data specified
* @param {!string} url - url to execute POST
* @param {FormData} formData - attach data to request POST
* @param {object} events - events allowed, xhr.process
* @param {number} timeout - timeout in milliseconds
* @param {object} headers - headers of request
* @param {object} parameters - parameters of request
* @param {string} serviceBaseURL - base of the uri petition
* @return {Promise}
*/
post_multipart(url, formData, events, timeout, headers, parameters, serviceBaseURL) {
const _url = this._createUrl(url, parameters, serviceBaseURL)
console.info('POST_MULTIPART', _url)
let req = request.post(_url);
this._prepareMultipartForm(formData, req);
return this._createPromiseRequest(req, events, timeout, headers);
}
/**
* Invoke PUT action to url and data specified
* @param {!string} url - url to execute PUT
* @param {object} data - attach data to request PUT
* @param {number} timeout - timeout in milliseconds
* @param {object} headers - headers of request
* @param {object} parameters - parameters of request
* @param {string} serviceBaseURL - base of the uri petition
* @return {Promise}
*/
put(url, data, timeout, headers, parameters, serviceBaseURL) {
const _url = this._createUrl(url, parameters, serviceBaseURL)
console.info('PUT', _url)
var req = request.put(_url).send(data);
if (headers) {
headers['Content-Type'] = 'application/json';
} else {
headers = {
'Content-Type': 'application/json'
};
}
return this._createPromiseRequest(req, null, timeout, headers);
}
/**
* Invoke put multipart action to url and data specified
* @param {!string} url - url to execute POST
* @param {FormData} formData - attach data to request POST
* @param {object} events - events allowed, xhr.process
* @param {number} timeout - timeout in milliseconds
* @param {object} headers - headers of request
* @param {object} parameters - parameters of request
* @param {string} serviceBaseURL - base of the uri petition
* @return {Promise}
*/
put_multipart(url, formData, events, timeout, headers, parameters, serviceBaseURL) {
const _url = this._createUrl(url, parameters, serviceBaseURL)
console.info('PUT_MULTIPART', _url)
let req = request.put(_url);
this._prepareMultipartForm(formData, req);
return this._createPromiseRequest(req, events, timeout, headers);
}
_prepareMultipartForm(formData, req) {
let sendFormData = true
const formDataKeys = Object.keys(formData)
formDataKeys.forEach(key => {
switch (key) {
case 'meta':
case 'json':
case 'file':
req.field(key, formData[key]);
delete formData[key]
break
case 'metadata':
req.attach(key, formData[key]);
sendFormData = false
break
case 'hardwareMedia':
case 'certificate':
case 'processorBulkFile':
req.attach('file', formData[key]);
sendFormData = false
break
case 'files':
formData[key].forEach((item, index) => {
// Esto controla si viene de node (con path) o de web (sin path)
if (item.path) {
var fileName = item.path.replace(/^.*[\\\/]/, '')
var contentType = mime.lookup(fileName);
if (contentType) {
req.attach(key, item, { filename: fileName, contentType: contentType });
} else if (fileName.endsWith('.py')) {
req.attach(key, item, { filename: fileName, contentType: 'text/x-python' });
} else {
req.attach(key, item, { filename: fileName });
}
} else {
req.attach(key, item);
}
})
delete formData[key]
sendFormData = false
break
case 'script':
case 'modelFile':
req.field(key, formData[key]);
delete formData[key]
sendFormData = false
break
case 'bulkFile':
req.set('Content-Type', formData.ext);
formData = formData.bulkFile;
break
default:
break;
}
})
if (sendFormData)
req.send(formData);
}
/**
* Invoke DELETE action to url specified
* @param {!string} url - url to execute DELETE
* @param {number} timeout - timeout in milliseconds
* @param {object} headers - headers of request
* @param {object} parameters - parameters of request
* @param {object} body - body of request
* @param {string} serviceBaseURL - base of the uri petition
* @return {Promise}
*/
delete(url, timeout, headers, parameters, body, serviceBaseURL) {
const _url = this._createUrl(url, parameters, serviceBaseURL)
console.info('DELETE', _url)
var req
if (body) {
req = request.del(_url).send(body);
//req = request('DELETE', url)
} else {
req = request.del(_url);
}
return this._createPromiseRequest(req, null, timeout, headers);
}
_createUrl(relativeUrl, parameters, serviceBaseURL) {
var encode = [];
if (parameters) {
var keys = Object.keys(parameters);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var queryParameter = key + '=' + parameters[key];
if (i === 0) {
relativeUrl = relativeUrl + '?' + queryParameter;
} else {
relativeUrl = relativeUrl + '&' + queryParameter;
}
}
// console.log(JSON.stringify(parameters));
}
// console.log(relativeUrl);
var relativeUrlSplit = relativeUrl.split("/");
var length = relativeUrlSplit.length;
relativeUrlSplit.forEach(function (item, index) {
if (index === (length - 1) && item.indexOf("?") > 0) {
var parameters = item.substring(item.indexOf("?"), item.length);
var _item = item.substring(0, item.indexOf("?"));
encode.push(urlencode(_item) + parameters);
} else {
encode.push(urlencode(item));
}
});
return this._url(this._options) + "/" + this._getDefaultBaseURL(serviceBaseURL) + '/' + encode.join("/");
}
_getDefaultBaseURL(serviceBaseURL) {
if (!serviceBaseURL) {
if (this._isSouth) {
return 'v80'
} else {
return 'north/v80'
}
}
return serviceBaseURL
}
_createPromiseRequest(req, events, timeout, headers, asBlob) {
let _timeout = timeout;
if (typeof _timeout === "undefined" || _timeout === null) {
_timeout = this._options.timeout;
}
let defered = q.defer();
let promise = defered.promise;
let apiKey = this._options.apiKey;
let JWT = this._options.jwt;
let _req = _timeout === -1 ? req : req.timeout(_timeout);
if (JWT && !this._isSouth) {
_req = _req.set('Authorization', 'Bearer ' + JWT);
}
else if (apiKey) {
_req = _req.set('X-ApiKey', this._options.apiKey);
}
if (headers) {
var keys = Object.keys(headers);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (headers[key] !== undefined)
_req = _req.set(key, headers[key]);
}
}
if (events) {
for (let event in events) {
_req = _req.on(event, events[event]);
}
}
if (asBlob) {
req.responseType('blob')
}
_req = _req.end(function (err, res) {
if (err !== null) {
console.error("OGAPI ERROR: ")
try {
console.log(JSON.stringify(err))
} catch (err) {
console.log(err)
}
let data;
let headers;
let status = err.status ? err.status : undefined;
let errorMessage = {
errors: [{
code: status,
message: 'OGAPI: Something is broken. Please contact with your administrator.'
}]
};
if (typeof err.response !== "undefined") {
data = err.response.body ? err.response.body : errorMessage;
headers = err.response.headers
status = err.status;
} else {
if (!status) {
data = errorMessage;
status = 500;
} else {
data = err.message;
status = 408;
}
}
defered.reject({
statusCode: status,
'data': data,
headers: headers
});
} else {
defered.resolve(res);
}
});
return promise;
}
}