d2-ui
Version:
273 lines (219 loc) • 12.2 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var _libCheck = require('../lib/check');
var _libUtils = require('../lib/utils');
var _systemSystem = require('../system/System');
var _systemSystem2 = _interopRequireDefault(_systemSystem);
require('whatwg-fetch');
function getMergeStrategyParam() {
var mergeType = arguments.length <= 0 || arguments[0] === undefined ? 'REPLACE' : arguments[0];
var system = _systemSystem2['default'].getSystem();
if (system.version && Number(system.version.minor) <= 22) {
return 'mergeStrategy=' + mergeType;
}
return 'mergeMode=' + mergeType;
}
function getUrl(baseUrl, url) {
// If we are dealing with an absolute url use that instead
if (new RegExp('^(:?https?:)?//').test(url)) {
return url;
}
var urlParts = [];
if (baseUrl) {
urlParts.push(baseUrl);
}
urlParts.push(url);
return urlParts.join('/').replace(new RegExp('(.(?:[^:]))\/\/+', 'g'), '$1/').replace(new RegExp('\/$'), '');
}
var Api = (function () {
function Api(fetchImpl) {
_classCallCheck(this, Api);
// Optionally provide fetch to the constructor so it can be mocked during testing
if (typeof fetchImpl === 'function') {
this.fetch = fetchImpl.bind(typeof window !== 'undefined' ? window : global);
} else if (typeof fetch !== 'undefined') {
this.fetch = fetch.bind(typeof window !== 'undefined' ? window : global);
} else {
throw new Error('Failed to initialise D2 Api: No fetch implementation is available');
}
this.baseUrl = '/api';
this.defaultFetchOptions = {
mode: 'cors', // requests to different origins fail
credentials: 'include', // include cookies with same-origin requests
cache: 'default', // See https://fetch.spec.whatwg.org/#concept-request-cache-mode,
headers: new Headers()
};
}
_createClass(Api, [{
key: 'get',
value: function get(url, data, options) {
return this.request('GET', getUrl(this.baseUrl, url), data, options);
}
/* eslint-disable complexity */
}, {
key: 'post',
value: function post(url, data) {
var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
var requestUrl = getUrl(this.baseUrl, url);
var payload = data;
// Ensure that headers are defined and are treated without case sensitivity
options.headers = new Headers(options.headers || {}); // eslint-disable-line
// Pass data through JSON.stringify, unless options.contentType is 'text/plain' or false (meaning don't process)
// TODO: Deprecated - remove in v26
if (options.contentType) {
// Display a deprecation warning, except during test
if (!process.env || process.env.npm_lifecycle_event !== 'test') {
var e = new Error();
console.warn( // eslint-disable-line
'Deprecation warning: Setting `contentType` for API POST requests is deprecated, and support may ' + 'be removed in the next major release of D2. In stead you may set the `Content-Type` header ' + 'explicitly. If no `Content-Type` header is specified, the browser will try to determine one for ' + 'you.\nRequest:', 'POST', requestUrl, e.stack);
}
options.headers.set('Content-Type', 'text/plain');
delete options.contentType; // eslint-disable-line
} else if (data.constructor.name === 'FormData' && !options.headers.get('Content-Type')) {
options.headers.set('Content-Type', 'multipart/form-data');
payload = data;
} else {
payload = JSON.stringify(data);
}
return this.request('POST', requestUrl, payload, options);
}
/* eslint-enable complexity */
}, {
key: 'delete',
value: function _delete(url, options) {
return this.request('DELETE', getUrl(this.baseUrl, url), undefined, options);
}
}, {
key: 'update',
value: function update(url, data) {
var useMergeStrategy = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2];
// Since we are currently using PUT to save the full state back, we have to use mergeMode=REPLACE
// to clear out existing values
var urlForUpdate = useMergeStrategy === true ? url + '?' + getMergeStrategyParam() : url;
return this.request('PUT', getUrl(this.baseUrl, urlForUpdate), JSON.stringify(data));
}
/* eslint-disable complexity */
}, {
key: 'request',
value: function request(method, url, data) {
var _this = this;
var options = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3];
(0, _libCheck.checkType)(method, 'string', 'Request type');
(0, _libCheck.checkType)(url, 'string', 'Url');
var api = this;
var requestUrl = url;
var query = '';
if (requestUrl.indexOf('?') !== -1) {
query = requestUrl.substr(requestUrl.indexOf('?') + 1);
requestUrl = requestUrl.substr(0, requestUrl.indexOf('?'));
}
// Transfer filter properties from the data object to the query string
if (data && Array.isArray(data.filter)) {
query = '' + query + (query.length ? '&' : '') + 'filter=' + data.filter.join('&filter=');
delete data.filter; // eslint-disable-line no-param-reassign
}
// When using the GET method, transform the data object to query parameters
if (data && method === 'GET') {
Object.keys(data).forEach(function (key) {
query = '' + query + (query.length > 0 ? '&' : '') + key + '=' + data[key];
});
}
function getOptions(mergeOptions, requestData) {
var resultOptions = Object.assign({}, api.defaultFetchOptions, mergeOptions);
var headers = new Headers(mergeOptions.headers || {});
resultOptions.method = method;
// Only set content type when there is data to send
// GET requests and requests without data do not need a Content-Type header
// 0 and false are valid requestData values and therefore should have a content type
if (resultOptions.method === 'GET' || !requestData && requestData !== 0 && requestData !== false) {
headers['delete']('Content-Type');
} else if (requestData) {
// resultOptions.dataType = options.dataType !== undefined ? options.dataType : 'json';
if (!headers.get('Content-Type')) {
headers.set('Content-Type', data.constructor.name === 'FormData' ? 'multipart/form-data' : 'application/json');
}
resultOptions.body = requestData;
}
// Handle the dataType option used by jQuery.ajax, but throw a deprecation warning
// TODO: Remove in 2.26
if (mergeOptions.dataType) {
// Display a deprecation warning, except during test
if (!process.env || process.env.npm_lifecycle_event !== 'test') {
var e = new Error();
console.warn( // eslint-disable-line
'Deprecation warning: Setting `dataType` for API requests is deprecated, and support may be ' + 'removed in the next major release of D2. In stead you should set the `Accept` header ' + 'directly.\nRequest:', resultOptions.method, requestUrl, e.stack);
}
if (mergeOptions.dataType === 'text') {
headers.set('Accept', 'text/plain');
delete resultOptions.dataType;
}
}
resultOptions.headers = headers;
return resultOptions;
}
if (query.length) {
requestUrl = requestUrl + '?' + (0, _libUtils.customEncodeURIComponent)(query);
}
var requestOptions = getOptions(options, options.method === 'GET' ? undefined : data);
// If the provided value is valid JSON, return the parsed JSON object. If not, return the raw value as is.
function parseResponseData(value) {
try {
return JSON.parse(value);
} catch (e) {
return value;
}
}
return new Promise(function (resolve, reject) {
// fetch returns a promise that will resolve with any response received from the server
// It will be rejected ONLY if no response is received from the server, i.e. because there's no internet
_this.fetch(requestUrl, requestOptions).then(function (response) {
// If the request failed, response.ok will be false and response.status will be the status code
if (response.ok) {
response.text().then(function (text) {
return resolve(parseResponseData(text));
});
} else {
response.text().then(function (text) {
if (!process.env || process.env.npm_lifecycle_event !== 'test') {
console.warn( // eslint-disable-line
'API request failed with status ' + response.status + ' ' + response.statusText + '\n', 'Request: ' + requestOptions.method + ' ' + requestUrl);
}
reject(parseResponseData(text));
});
}
})['catch'](function (err) {
// It's not usually possible to get much info about the cause of the error programmatically, but
// the user can check the browser console for more info
if (!process.env || process.env.npm_lifecycle_event !== 'test') {
console.error('Server connection error:', err); // eslint-disable-line
}
reject('Server connection failed for API request: ' + requestOptions.method + ' ' + requestUrl);
});
});
}
/* eslint-enable complexity */
}, {
key: 'setBaseUrl',
value: function setBaseUrl(baseUrl) {
(0, _libCheck.checkType)(baseUrl, 'string', 'Base url');
this.baseUrl = baseUrl;
return this;
}
}]);
return Api;
})();
function getApi() {
if (getApi.api) {
return getApi.api;
}
return getApi.api = new Api();
}
Api.getApi = getApi;
exports['default'] = Api;
module.exports = exports['default'];
//# sourceMappingURL=Api.js.map