rally-node-trevsmart
Version:
Customized Rally REST Toolkit for Node.js
127 lines (122 loc) • 3.88 kB
JavaScript
import axios from 'axios';
import _ from 'lodash';
import callbackify from './util/callbackify.js';
const generateError = errorMessages => {
const e = new Error(errorMessages[0]);
e.errors = errorMessages;
return e;
};
export default class Request {
constructor(options) {
this.wsapiUrl = `${options.server}/slm/webservice/${options.apiVersion}`;
// Create axios instance with default configuration
const axiosConfig = {
baseURL: this.wsapiUrl,
timeout: 30000,
withCredentials: true,
...options.requestOptions
};
this.httpRequest = axios.create(axiosConfig);
this._hasKey = options.requestOptions && options.requestOptions.headers && options.requestOptions.headers.zsessionid;
// Store cookies for session management
this._cookies = {};
}
getCookies() {
// Simple cookie management for compatibility
return Object.keys(this._cookies).map(name => ({
name,
value: this._cookies[name],
domain: new URL(this.wsapiUrl).hostname
}));
}
auth() {
return this.doRequest('get', {
url: '/security/authorize'
}).then(result => {
this._token = result.SecurityToken;
});
}
doSecuredRequest(method, options, callback) {
if (this._hasKey) {
return this.doRequest(method, options, callback);
}
const doRequest = () => {
const requestOptions = _.merge({}, options, {
qs: {
key: this._token
}
});
return this.doRequest(method, requestOptions);
};
let securedRequestPromise;
if (this._token) {
securedRequestPromise = doRequest();
} else {
securedRequestPromise = this.auth().then(doRequest);
}
callbackify(securedRequestPromise, callback);
return securedRequestPromise;
}
doRequest(method, options, callback) {
const doRequestPromise = new Promise((resolve, reject) => {
const axiosOptions = {
method: method.toUpperCase(),
url: options.url,
...options
};
// Handle query parameters
if (options.qs) {
axiosOptions.params = options.qs;
}
// Handle JSON body
if (options.json && typeof options.json === 'object') {
axiosOptions.data = options.json;
axiosOptions.headers = {
'Content-Type': 'application/json',
...axiosOptions.headers
};
}
// Remove axios-incompatible options
delete axiosOptions.qs;
delete axiosOptions.json;
this.httpRequest(axiosOptions).then(response => {
const body = response.data;
if (!body || !_.isObject(body)) {
reject(generateError([`${options.url}: ${response.status}! body=${body}`]));
} else {
const result = _.values(body)[0];
if (result && result.Errors && result.Errors.length) {
reject(generateError(result.Errors));
} else {
resolve(result);
}
}
}).catch(error => {
if (error.response) {
// Server responded with error status
reject(generateError([`${options.url}: ${error.response.status}! ${error.response.statusText}`]));
} else if (error.request) {
// Network error
reject(generateError([`Unable to connect to server: ${this.wsapiUrl}`]));
} else {
// Other error
reject(generateError([error.message]));
}
});
});
callbackify(doRequestPromise, callback);
return doRequestPromise;
}
get(options, callback) {
return this.doRequest('get', options, callback);
}
post(options, callback) {
return this.doSecuredRequest('post', options, callback);
}
put(options, callback) {
return this.doSecuredRequest('put', options, callback);
}
del(options, callback) {
return this.doSecuredRequest('delete', options, callback);
}
}