UNPKG

d2-ui

Version:
273 lines (219 loc) 12.2 kB
'use strict'; 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