rest-api-handler
Advanced tools
Comparing version 1.8.1 to 2.0.0
@@ -5,2 +5,12 @@ # Change Log | ||
## [2.0.0] 2018-11-16 | ||
### Changed | ||
- Formats name are changed and no longer exported from library by them self. They are accessible from Api.FORMATS | ||
- Converted from flow to typescript | ||
### Remove | ||
- defaultResponseProcessor method | ||
- docs config | ||
## [1.8.1] 2018-06-27 | ||
@@ -7,0 +17,0 @@ ### Fixed |
662
dist/Api.js
'use strict'; | ||
function _defineProperty(obj, key, value) { | ||
if (key in obj) { | ||
Object.defineProperty(obj, key, { | ||
value: value, | ||
enumerable: true, | ||
configurable: true, | ||
writable: true | ||
}); | ||
} else { | ||
obj[key] = value; | ||
} | ||
return obj; | ||
} | ||
function _objectSpread(target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i] != null ? arguments[i] : {}; | ||
var ownKeys = Object.keys(source); | ||
if (typeof Object.getOwnPropertySymbols === 'function') { | ||
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { | ||
return Object.getOwnPropertyDescriptor(source, sym).enumerable; | ||
})); | ||
} | ||
ownKeys.forEach(function (key) { | ||
_defineProperty(target, key, source[key]); | ||
}); | ||
} | ||
return target; | ||
} | ||
// processor can be instance of class | ||
/** | ||
* Resolve given processor. | ||
* | ||
* @param {Input} response - Response to process. | ||
* @param {Array<ProcessorAdapter>} list - Array of processors. | ||
* @param {Request} request - fetch request | ||
* @param {number} i - Index of current processor. | ||
* @returns {any} Processed response | ||
* @param response - Response to process. | ||
* @param list - Array of processors. | ||
* @param request - fetch request | ||
* @param i - Index of current processor. | ||
* @returns Processed response | ||
*/ | ||
async function resolveProcessors(response, list, request, i) { | ||
if (i === void 0) { | ||
i = 0; | ||
} | ||
/** | ||
* @ignore | ||
*/ | ||
function resolveProcessors(response, list, request) { | ||
var i = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; | ||
const processor = list[i]; | ||
var processor = list[i]; | ||
if (!processor) { | ||
return response; | ||
} | ||
if (!processor) { | ||
return Promise.resolve(response); | ||
} | ||
const processedResponse = typeof processor === 'function' ? await processor(response, request) : await processor.processResponse(response, request); | ||
return (typeof processor === 'function' ? processor(response) : processor.processResponse(response, request)).then(function (processedResponse) { | ||
if (list[i + 1]) { | ||
return resolveProcessors(processedResponse, list, request, i + 1); | ||
} | ||
if (list[i + 1]) { | ||
return resolveProcessors(processedResponse, list, request, i + 1); | ||
} | ||
return processedResponse; | ||
}); | ||
return processedResponse; | ||
} | ||
// processor can be function or instance of class | ||
/** | ||
* @desc Types of formats of data you can send through body of Fetch request. | ||
* @todo rename file to data-formats | ||
* @todo rename variables to JSON and FORM_DATA | ||
*/ | ||
var JSON_FORMAT = 'json'; | ||
/** | ||
* @desc Json is object converted to string. It is default format in a library. | ||
*/ | ||
const JSON$1 = 'json'; | ||
/** | ||
* @desc Form Data can be used to send images. | ||
* @see https://developer.mozilla.org/en-US/docs/Web/API/FormData | ||
*/ | ||
var FORM_DATA_FORMAT = 'formdata'; | ||
const FORM_DATA = 'formdata'; | ||
/** | ||
@@ -54,364 +86,338 @@ * @desc Url encoded data in body | ||
*/ | ||
var URL_ENCODED_FORMAT = 'urlencoded'; | ||
var classCallCheck = function (instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
}; | ||
const URL_ENCODED = 'urlencoded'; | ||
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); | ||
} | ||
} | ||
var FORMATS = ({ | ||
JSON: JSON$1, | ||
FORM_DATA: FORM_DATA, | ||
URL_ENCODED: URL_ENCODED | ||
}); | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
}; | ||
}(); | ||
var _extends = Object.assign || function (target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i]; | ||
for (var key in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
target[key] = source[key]; | ||
} | ||
} | ||
} | ||
return target; | ||
}; | ||
/** | ||
* Class for handling responses and requests. | ||
*/ | ||
var Api = function () { | ||
class Api { | ||
/** | ||
* Base api url | ||
*/ | ||
/** | ||
* Constructor. | ||
* | ||
* @param {string} apiUrl - Base api url | ||
* @param {Array<ProcessorAdapter>} processors - List of processors that parse response from server. | ||
* @param {Object} defaultHeaders - Base settings for Fetch Request | ||
* @param {RequestOptions} defaultOptions - List of processors that parse response from server. | ||
*/ | ||
/** | ||
* Base http headers | ||
*/ | ||
/** | ||
* Base settings for Fetch Request | ||
*/ | ||
/** | ||
* Base settings for Fetch Request | ||
*/ | ||
/** | ||
* List of processors that parse response from server. | ||
*/ | ||
/** | ||
* Base api url | ||
*/ | ||
function Api(apiUrl) { | ||
var processors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; | ||
var defaultHeaders = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
var defaultOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; | ||
classCallCheck(this, Api); | ||
/** | ||
* List of formatter you can use to process content of body request. | ||
*/ | ||
this.apiUrl = apiUrl; | ||
this.defaultHeaders = defaultHeaders; | ||
this.defaultOptions = defaultOptions; | ||
this.processors = processors; | ||
/** | ||
* Constructor. | ||
* | ||
* @param apiUrl - Base api url | ||
* @param processors - List of processors that parse response from server. | ||
* @param defaultHeaders - Base settings for Fetch Request | ||
* @param defaultOptions - List of processors that parse response from server. | ||
*/ | ||
constructor(apiUrl, processors, defaultHeaders, defaultOptions) { | ||
if (processors === void 0) { | ||
processors = []; | ||
} | ||
/** | ||
* Convert data in object to format of Fetch body. | ||
* | ||
* @param {Object} data - Data to convert | ||
* @param {Format} to - Format to which convert the data. Default is JSON. | ||
* @returns {string | FormData} Converted data | ||
* | ||
* @example | ||
* const body = Api.convertData({ a: 'b' }, Api.FORMATS.JSON_FORMAT); | ||
* // output is {"a":"b"} | ||
*/ | ||
if (defaultHeaders === void 0) { | ||
defaultHeaders = {}; | ||
} | ||
if (defaultOptions === void 0) { | ||
defaultOptions = {}; | ||
} | ||
/** | ||
* List of formatter you can use to process content of body request. | ||
* | ||
* @type {{JSON_FORMAT: string, FORM_DATA_FORMAT: string}} | ||
*/ | ||
_defineProperty(this, "apiUrl", void 0); | ||
_defineProperty(this, "defaultHeaders", void 0); | ||
/** | ||
* List of processors that parse response from server. | ||
*/ | ||
_defineProperty(this, "defaultOptions", void 0); | ||
_defineProperty(this, "processors", void 0); | ||
/** | ||
* Base http headers | ||
*/ | ||
this.apiUrl = apiUrl; | ||
this.defaultHeaders = defaultHeaders; | ||
this.defaultOptions = defaultOptions; | ||
this.processors = processors; | ||
} | ||
/** | ||
* Convert data in object to format of Fetch body. | ||
* | ||
* @param data - Data to convert | ||
* @param to - Format to which convert the data. Default is JSON. | ||
* @returns Converted data | ||
* | ||
* @example | ||
* const body = Api.convertData({ a: 'b' }, Api.FORMATS.JSON); | ||
* // output is {"a":"b"} | ||
*/ | ||
createClass(Api, [{ | ||
key: 'setDefaultHeaders', | ||
static convertData(data, to) { | ||
if (to === void 0) { | ||
to = JSON$1; | ||
} | ||
if (to === FORM_DATA) { | ||
const formData = new FormData(); | ||
Object.entries(data).forEach((_ref) => { | ||
let key = _ref[0], | ||
value = _ref[1]; | ||
formData.append(key, value); | ||
}); | ||
return formData; | ||
} | ||
/** | ||
* Set default headers. | ||
* | ||
* @param {Headers} headers - HTTP headers | ||
*/ | ||
value: function setDefaultHeaders(headers) { | ||
this.defaultHeaders = headers; | ||
} | ||
if (to === URL_ENCODED) { | ||
return Api.convertParametersToUrl(data).slice(1); | ||
} | ||
/** | ||
* Add default HTTP header. | ||
* | ||
* @param {string} name - Name of header | ||
* @param {string} value - Value for header | ||
* @example | ||
* api.setDefaultHeader('content-type', 'application/json'); | ||
*/ | ||
return JSON.stringify(data); | ||
} | ||
/** | ||
* Convert object to url parameters string. | ||
* | ||
* @param parameters - List of parameters | ||
* @returns Encoded string with ? prefix and variables separated by & | ||
* | ||
* @example | ||
* const parameters = Api.convertData({ a: '%b%' }); | ||
* // output is ?a=%25b%25 | ||
*/ | ||
}, { | ||
key: 'setDefaultHeader', | ||
value: function setDefaultHeader(name, value) { | ||
this.defaultHeaders[name] = value; | ||
} | ||
/** | ||
* Remove default header. | ||
* | ||
* @param {string} name - Name of header | ||
*/ | ||
static convertParametersToUrl(parameters) { | ||
const keys = Object.keys(parameters); | ||
}, { | ||
key: 'removeDefaultHeader', | ||
value: function removeDefaultHeader(name) { | ||
delete this.defaultHeaders[name]; | ||
} | ||
if (keys.length === 0) { | ||
return ''; | ||
} | ||
/** | ||
* Get default headers. | ||
* | ||
* @returns {Headers} - Get Default headers | ||
*/ | ||
return `?${keys.map(key => { | ||
return `${key}=${encodeURIComponent(parameters[key])}`; | ||
}).join('&')}`; | ||
} | ||
/** | ||
* Set default headers. | ||
* | ||
* @param headers - HTTP headers | ||
*/ | ||
}, { | ||
key: 'getDefaultHeaders', | ||
value: function getDefaultHeaders() { | ||
return this.defaultHeaders; | ||
} | ||
/** | ||
* Fetch API url. | ||
* | ||
* @protected | ||
* @param {Request} request - Fetch request | ||
* @returns {Promise<Response>} Fetch response | ||
*/ | ||
setDefaultHeaders(headers) { | ||
this.defaultHeaders = headers; | ||
} | ||
/** | ||
* Add default HTTP header. | ||
* | ||
* @param name - Name of header | ||
* @param value - Value for header | ||
* @example | ||
* api.setDefaultHeader('content-type', 'application/json'); | ||
*/ | ||
}, { | ||
key: 'fetchRequest', | ||
value: function fetchRequest(request) { | ||
return fetch(request); | ||
} | ||
/** | ||
* Request given API endpoint. | ||
* | ||
* @param {string} namespace - Api endpoint or full url | ||
* @param {MethodType} method - Request method eg. POST or GET | ||
* @param {RequestOptions} options - Fetch options | ||
* @param {Object} headers - Custom headers | ||
* @returns {Promise<ProcessedResponse>} processed response | ||
* @example | ||
* const { data } = await api.request('ad', 'POST', { | ||
* body: '{"ad":1}' | ||
* }) | ||
* | ||
* const { data } = await api.request('http://i-can-request-full-url.com/?a=b', 'GET') | ||
*/ | ||
setDefaultHeader(name, value) { | ||
this.defaultHeaders[name] = value; | ||
} | ||
/** | ||
* Remove default header. | ||
* | ||
* @param name - Name of header | ||
*/ | ||
}, { | ||
key: 'request', | ||
value: function request(namespace, method) { | ||
var _this = this; | ||
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
var headers = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; | ||
removeDefaultHeader(name) { | ||
delete this.defaultHeaders[name]; | ||
} | ||
/** | ||
* Get default headers. | ||
* | ||
* @returns Get Default headers | ||
*/ | ||
var urlToRequest = namespace.indexOf('http') === 0 ? namespace : this.apiUrl + '/' + namespace; | ||
var request = new Request(urlToRequest, _extends({}, this.defaultOptions, { | ||
method: method, | ||
headers: new Headers(_extends({}, this.getDefaultHeaders(), headers)) | ||
}, options)); | ||
getDefaultHeaders() { | ||
return this.defaultHeaders; | ||
} | ||
/** | ||
* Fetch API url. | ||
* | ||
* @protected | ||
* @param request - Fetch request | ||
* @returns Fetch response | ||
*/ | ||
return this.fetchRequest(request).then(function (response) { | ||
return resolveProcessors(response, _this.processors, request); | ||
}); | ||
} | ||
/** | ||
* Send a request with body. | ||
* | ||
* @protected | ||
* @param {string} namespace - api endpoint | ||
* @param {MethodType} method - api method | ||
* @param {Object} data - body JSON parameters | ||
* @param {Format} format - format of body request | ||
* @param {Object} headers - custom headers | ||
* @returns {Promise<ProcessedResponse>} processed response | ||
*/ | ||
fetchRequest(request) { | ||
return fetch(request); | ||
} | ||
/** | ||
* Request given API endpoint. | ||
* | ||
* @param namespace - Api endpoint or full url | ||
* @param method - Request method eg. POST or GET | ||
* @param options - Fetch options | ||
* @param headers - Custom headers | ||
* @returns processed response | ||
* @example | ||
* const { data } = await api.request('ad', 'POST', { | ||
* body: '{"ad":1}' | ||
* }) | ||
* | ||
* const { data } = await api.request('http://i-can-request-full-url.com/?a=b', 'GET') | ||
*/ | ||
}, { | ||
key: 'requestWithBody', | ||
value: function requestWithBody(namespace, method, data, format) { | ||
var headers = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; | ||
return this.request(namespace, method, { | ||
body: Api.convertData(data, format) | ||
}, headers); | ||
} | ||
request(namespace, method, options, headers) { | ||
if (options === void 0) { | ||
options = {}; | ||
} | ||
/** | ||
* Send a GET request. | ||
* | ||
* @param {string} namespace - api endpoint | ||
* @param {Object} parameters - get parameters | ||
* @param {Object} headers - custom headers | ||
* @returns {Promise<ProcessedResponse>} processed response | ||
* | ||
* @example | ||
* const { data } = await api.get('brand', { id: 5 }) | ||
* // will call YOUR_URI/brand?id=5 | ||
* console.log(data); | ||
*/ | ||
if (headers === void 0) { | ||
headers = {}; | ||
} | ||
}, { | ||
key: 'get', | ||
value: function get$$1(namespace) { | ||
var parameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var headers = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
const urlToRequest = namespace.indexOf('http') === 0 ? namespace : `${this.apiUrl}/${namespace}`; | ||
const request = new Request(urlToRequest, _objectSpread({}, this.defaultOptions, { | ||
method, | ||
// @ts-ignore | ||
headers: new Headers(_objectSpread({}, this.getDefaultHeaders(), headers)) | ||
}, options)); | ||
return this.fetchRequest(request).then(response => { | ||
return resolveProcessors(response, this.processors, request); | ||
}); | ||
} | ||
/** | ||
* Send a request with body. | ||
* | ||
* @protected | ||
* @param namespace - api endpoint | ||
* @param method - api method | ||
* @param data - body JSON parameters | ||
* @param format - format of body request | ||
* @param headers - custom headers | ||
* @returns processed response | ||
*/ | ||
return this.request('' + namespace + Api.convertParametersToUrl(parameters), 'GET', {}, headers); | ||
} | ||
/** | ||
* Send a POST request. | ||
* | ||
* @param {string} namespace - Api endpoint | ||
* @param {Object} data - Request object | ||
* @param {?Format} format - Format of body request | ||
* @param {Object} headers - custom headers | ||
* @returns {Promise<ProcessedResponse>} Processed response | ||
*/ | ||
requestWithBody(namespace, method, data, format, headers) { | ||
if (headers === void 0) { | ||
headers = {}; | ||
} | ||
}, { | ||
key: 'post', | ||
value: function post(namespace) { | ||
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var format = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : JSON_FORMAT; | ||
var headers = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; | ||
return this.request(namespace, method, { | ||
body: Api.convertData(data, format) | ||
}, headers); | ||
} | ||
/** | ||
* Send a GET request. | ||
* | ||
* @param namespace - api endpoint | ||
* @param parameters - get parameters | ||
* @param headers - custom headers | ||
* @returns processed response | ||
* | ||
* @example | ||
* const { data } = await api.get('brand', { id: 5 }) | ||
* // will call YOUR_URI/brand?id=5 | ||
* console.log(data); | ||
*/ | ||
return this.requestWithBody(namespace, 'POST', data, format, headers); | ||
} | ||
/** | ||
* Send a PUT request. | ||
* | ||
* @param {string} namespace - Api endpoint | ||
* @param {Object} data - Request object | ||
* @param {?Format} format - Format of body request | ||
* @param {Object} headers - custom headers | ||
* @returns {Promise<ProcessedResponse>} Processed response | ||
*/ | ||
get(namespace, parameters, headers) { | ||
if (parameters === void 0) { | ||
parameters = {}; | ||
} | ||
}, { | ||
key: 'put', | ||
value: function put(namespace) { | ||
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var format = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : JSON_FORMAT; | ||
var headers = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; | ||
if (headers === void 0) { | ||
headers = {}; | ||
} | ||
return this.requestWithBody(namespace, 'PUT', data, format, headers); | ||
} | ||
return this.request(`${namespace}${Api.convertParametersToUrl(parameters)}`, 'GET', {}, headers); | ||
} | ||
/** | ||
* Send a POST request. | ||
* | ||
* @param namespace - Api endpoint | ||
* @param data - Request object | ||
* @param format - Format of body request | ||
* @param headers - custom headers | ||
* @returns Processed response | ||
*/ | ||
/** | ||
* Send a DELETE request. | ||
* | ||
* @param {string} namespace - Api endpoint | ||
* @param {Object} headers - custom headers | ||
* @returns {Promise<ProcessedResponse>} Processed response | ||
*/ | ||
}, { | ||
key: 'delete', | ||
value: function _delete(namespace) { | ||
var headers = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
post(namespace, data, format, headers) { | ||
if (data === void 0) { | ||
data = {}; | ||
} | ||
return this.request(namespace, 'DELETE', {}, headers); | ||
} | ||
}], [{ | ||
key: 'convertData', | ||
value: function convertData(data) { | ||
var to = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : JSON_FORMAT; | ||
if (format === void 0) { | ||
format = JSON$1; | ||
} | ||
if (to === FORM_DATA_FORMAT) { | ||
var formData = new FormData(); | ||
Object.keys(data).forEach(function (key) { | ||
var value = data[key]; | ||
formData.append(key, typeof value === 'number' ? value.toString() : value); | ||
}); | ||
return formData; | ||
} | ||
if (headers === void 0) { | ||
headers = {}; | ||
} | ||
if (to === URL_ENCODED_FORMAT) { | ||
return Api.convertParametersToUrl(data).slice(1); | ||
} | ||
return this.requestWithBody(namespace, 'POST', data, format, headers); | ||
} | ||
/** | ||
* Send a PUT request. | ||
* | ||
* @param namespace - Api endpoint | ||
* @param data - Request object | ||
* @param format - Format of body request | ||
* @param headers - custom headers | ||
* @returns Processed response | ||
*/ | ||
return JSON.stringify(data); | ||
} | ||
/** | ||
* Convert object to url parameters string. | ||
* | ||
* @param {Object} parameters - List of parameters | ||
* @returns {string} Encoded string with ? prefix and variables separated by & | ||
* | ||
* @example | ||
* const parameters = Api.convertData({ a: '%b%' }); | ||
* // output is ?a=%25b%25 | ||
*/ | ||
put(namespace, data, format, headers) { | ||
if (data === void 0) { | ||
data = {}; | ||
} | ||
}, { | ||
key: 'convertParametersToUrl', | ||
value: function convertParametersToUrl(parameters) { | ||
var keys = Object.keys(parameters); | ||
if (format === void 0) { | ||
format = JSON$1; | ||
} | ||
if (keys.length === 0) { | ||
return ''; | ||
} | ||
if (headers === void 0) { | ||
headers = {}; | ||
} | ||
return '?' + keys.map(function (key) { | ||
var value = parameters[key]; | ||
return key + '=' + encodeURIComponent(typeof value === 'number' ? value.toString() : value); | ||
}).join('&'); | ||
} | ||
}]); | ||
return Api; | ||
}(); | ||
return this.requestWithBody(namespace, 'PUT', data, format, headers); | ||
} | ||
/** | ||
* Send a DELETE request. | ||
* | ||
* @param namespace - Api endpoint | ||
* @param headers - custom headers | ||
* @returns Processed response | ||
*/ | ||
Api.FORMATS = { | ||
JSON_FORMAT: JSON_FORMAT, | ||
FORM_DATA_FORMAT: FORM_DATA_FORMAT, | ||
URL_ENCODED_FORMAT: URL_ENCODED_FORMAT | ||
}; | ||
delete(namespace, headers) { | ||
if (headers === void 0) { | ||
headers = {}; | ||
} | ||
return this.request(namespace, 'DELETE', {}, headers); | ||
} | ||
} | ||
_defineProperty(Api, "FORMATS", FORMATS); | ||
module.exports = Api; |
'use strict'; | ||
var classCallCheck = function (instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
function _defineProperty(obj, key, value) { | ||
if (key in obj) { | ||
Object.defineProperty(obj, key, { | ||
value: value, | ||
enumerable: true, | ||
configurable: true, | ||
writable: true | ||
}); | ||
} else { | ||
obj[key] = value; | ||
} | ||
}; | ||
var inherits = function (subClass, superClass) { | ||
if (typeof superClass !== "function" && superClass !== null) { | ||
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); | ||
} | ||
return obj; | ||
} | ||
subClass.prototype = Object.create(superClass && superClass.prototype, { | ||
constructor: { | ||
value: subClass, | ||
enumerable: false, | ||
writable: true, | ||
configurable: true | ||
} | ||
}); | ||
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; | ||
}; | ||
/* eslint-disable no-proto */ | ||
var possibleConstructorReturn = function (self, call) { | ||
if (!self) { | ||
throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); | ||
} | ||
return call && (typeof call === "object" || typeof call === "function") ? call : self; | ||
}; | ||
/** | ||
* Default API Exception | ||
*/ | ||
class DefaultApiException extends Error { | ||
/** | ||
* Response from server that throwed an error. | ||
*/ | ||
/* eslint-disable no-proto */ | ||
var DefaultApiException = function (_Error) { | ||
inherits(DefaultApiException, _Error); | ||
/** | ||
* Request that failed. | ||
*/ | ||
@@ -44,31 +35,29 @@ /** | ||
* | ||
* @param {ProcessedResponse} response - Processed response from server. | ||
* @param {Request} request - Fetch Request. | ||
* @param response - Processed response from server. | ||
* @param request - Fetch Request. | ||
*/ | ||
constructor(response, request) { | ||
super(`Api exception: ${JSON.stringify(response.data)}`); | ||
/** | ||
* Response from server that throwed an error. | ||
*/ | ||
function DefaultApiException(response, request) { | ||
classCallCheck(this, DefaultApiException); | ||
_defineProperty(this, "response", void 0); | ||
var _this = possibleConstructorReturn(this, (DefaultApiException.__proto__ || Object.getPrototypeOf(DefaultApiException)).call(this, 'Api exception: ' + JSON.stringify(response.data))); | ||
_defineProperty(this, "request", void 0); | ||
_this.response = response; | ||
_this.request = request; | ||
this.response = response; | ||
this.request = request; // babel bug - https://github.com/babel/babel/issues/4485 | ||
// @ts-ignore | ||
// babel bug - https://github.com/babel/babel/issues/4485 | ||
// $FlowFixMe | ||
_this.__proto__ = DefaultApiException.prototype; | ||
return _this; | ||
this.__proto__ = DefaultApiException.prototype; | ||
} | ||
/** | ||
* Request that failed. | ||
*/ | ||
getResponse() { | ||
return this.response; | ||
} | ||
getRequest() { | ||
return this.request; | ||
} | ||
return DefaultApiException; | ||
}(Error); | ||
} | ||
module.exports = DefaultApiException; |
'use strict'; | ||
/** | ||
* Decode API body response. | ||
* | ||
* @param {Response} response - Native response. | ||
* @returns {DecodedStream} Decoded json or simple string. | ||
*/ | ||
function decodeResponse(response) { | ||
var contentType = response.headers.get('content-type'); | ||
function _defineProperty(obj, key, value) { | ||
if (key in obj) { | ||
Object.defineProperty(obj, key, { | ||
value: value, | ||
enumerable: true, | ||
configurable: true, | ||
writable: true | ||
}); | ||
} else { | ||
obj[key] = value; | ||
} | ||
// on default decode response as text | ||
if (!contentType) { | ||
return response.text(); | ||
} | ||
if (contentType.indexOf('json') >= 0) { | ||
return response.json(); | ||
} | ||
if (contentType.indexOf('text') >= 0 || contentType.indexOf('xml') >= 0) { | ||
return response.text(); | ||
} | ||
return response.blob(); | ||
return obj; | ||
} | ||
/** | ||
* Process response from API. | ||
* | ||
* @param {Response} response - Native response. | ||
* @param {BodyDecoder} decoder - Custom body decoder. | ||
* @returns {Promise<ProcessedResponse>} Processed response from API. | ||
* Processor provider that process response from API and throw custom Exception. | ||
*/ | ||
function responseProcessor(response) { | ||
var decoder = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : decodeResponse; | ||
class DefaultResponseProcessor { | ||
/** | ||
* Constructor. | ||
* | ||
* @param Exception - Exception class that will be throwed if request fails. | ||
* @param decoder - Define custom response body decoder. | ||
*/ | ||
constructor(Exception, decoder) { | ||
_defineProperty(this, "Exception", void 0); | ||
return decoder(response).then(function (decodedResponse) { | ||
// create custom response format | ||
var toRespond = { | ||
data: decodedResponse, | ||
status: response.status, | ||
source: response | ||
}; | ||
_defineProperty(this, "decoder", void 0); | ||
// response ok means that response was successful (2xx) | ||
if (response.ok) { | ||
return toRespond; | ||
} | ||
this.Exception = Exception; | ||
this.decoder = decoder || DefaultResponseProcessor.decodeResponse; | ||
} | ||
// otherwise create an error | ||
throw toRespond; | ||
}); | ||
} | ||
async processResponse(response, request) { | ||
const decodedResponse = await this.decoder(response); | ||
const toRespond = { | ||
data: decodedResponse, | ||
status: response.status, | ||
source: response | ||
}; | ||
var classCallCheck = function (instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
}; | ||
if (!response.ok) { | ||
throw new this.Exception(toRespond, request); | ||
} | ||
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 toRespond; | ||
} | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
}; | ||
}(); | ||
static decodeResponse(response) { | ||
const contentType = response.headers.get('content-type'); // on default decode response as text | ||
/** | ||
* Processor provider that process response from API and throw custom Exception. | ||
*/ | ||
var DefaultResponseProcessor = function () { | ||
if (!contentType) { | ||
return response.text(); | ||
} | ||
/** | ||
* Constructor. | ||
* | ||
* @param {Class<ApiExceptionInterface>} Exception - Exception class that will be throwed if request fails. | ||
* @param {Function} decoder - Define custom response body decoder. | ||
*/ | ||
function DefaultResponseProcessor(Exception) { | ||
var decoder = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : decodeResponse; | ||
classCallCheck(this, DefaultResponseProcessor); | ||
this.decoder = decodeResponse; | ||
if (contentType.indexOf('json') >= 0) { | ||
return response.json(); | ||
} | ||
this.Exception = Exception; | ||
this.decoder = decoder; | ||
this.processResponse = this.processResponse.bind(this); | ||
if (contentType.indexOf('text') >= 0 || contentType.indexOf('xml') >= 0) { | ||
return response.text(); | ||
} | ||
/** | ||
* Process response from API. | ||
* | ||
* @param {Response} response - Native fetch response | ||
* @param {Request} request - Native fetch request | ||
* @returns {Promise<ProcessedResponse>} Processed response. | ||
*/ | ||
return response.blob(); | ||
} | ||
} | ||
createClass(DefaultResponseProcessor, [{ | ||
key: 'processResponse', | ||
value: function processResponse(response, request) { | ||
var _this = this; | ||
return responseProcessor(response, this.decoder).catch(function (exception) { | ||
if (exception.data && exception.status && exception.source) { | ||
throw new _this.Exception(exception, request); | ||
} | ||
throw exception; | ||
}); | ||
} | ||
}]); | ||
return DefaultResponseProcessor; | ||
}(); | ||
module.exports = DefaultResponseProcessor; |
@@ -5,49 +5,81 @@ 'use strict'; | ||
function _defineProperty(obj, key, value) { | ||
if (key in obj) { | ||
Object.defineProperty(obj, key, { | ||
value: value, | ||
enumerable: true, | ||
configurable: true, | ||
writable: true | ||
}); | ||
} else { | ||
obj[key] = value; | ||
} | ||
return obj; | ||
} | ||
function _objectSpread(target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i] != null ? arguments[i] : {}; | ||
var ownKeys = Object.keys(source); | ||
if (typeof Object.getOwnPropertySymbols === 'function') { | ||
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { | ||
return Object.getOwnPropertyDescriptor(source, sym).enumerable; | ||
})); | ||
} | ||
ownKeys.forEach(function (key) { | ||
_defineProperty(target, key, source[key]); | ||
}); | ||
} | ||
return target; | ||
} | ||
// processor can be instance of class | ||
/** | ||
* Resolve given processor. | ||
* | ||
* @param {Input} response - Response to process. | ||
* @param {Array<ProcessorAdapter>} list - Array of processors. | ||
* @param {Request} request - fetch request | ||
* @param {number} i - Index of current processor. | ||
* @returns {any} Processed response | ||
* @param response - Response to process. | ||
* @param list - Array of processors. | ||
* @param request - fetch request | ||
* @param i - Index of current processor. | ||
* @returns Processed response | ||
*/ | ||
async function resolveProcessors(response, list, request, i) { | ||
if (i === void 0) { | ||
i = 0; | ||
} | ||
/** | ||
* @ignore | ||
*/ | ||
function resolveProcessors(response, list, request) { | ||
var i = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; | ||
const processor = list[i]; | ||
var processor = list[i]; | ||
if (!processor) { | ||
return response; | ||
} | ||
if (!processor) { | ||
return Promise.resolve(response); | ||
} | ||
const processedResponse = typeof processor === 'function' ? await processor(response, request) : await processor.processResponse(response, request); | ||
return (typeof processor === 'function' ? processor(response) : processor.processResponse(response, request)).then(function (processedResponse) { | ||
if (list[i + 1]) { | ||
return resolveProcessors(processedResponse, list, request, i + 1); | ||
} | ||
if (list[i + 1]) { | ||
return resolveProcessors(processedResponse, list, request, i + 1); | ||
} | ||
return processedResponse; | ||
}); | ||
return processedResponse; | ||
} | ||
// processor can be function or instance of class | ||
/** | ||
* @desc Types of formats of data you can send through body of Fetch request. | ||
* @todo rename file to data-formats | ||
* @todo rename variables to JSON and FORM_DATA | ||
*/ | ||
var JSON_FORMAT = 'json'; | ||
/** | ||
* @desc Json is object converted to string. It is default format in a library. | ||
*/ | ||
const JSON$1 = 'json'; | ||
/** | ||
* @desc Form Data can be used to send images. | ||
* @see https://developer.mozilla.org/en-US/docs/Web/API/FormData | ||
*/ | ||
var FORM_DATA_FORMAT = 'formdata'; | ||
const FORM_DATA = 'formdata'; | ||
/** | ||
@@ -57,495 +89,405 @@ * @desc Url encoded data in body | ||
*/ | ||
var URL_ENCODED_FORMAT = 'urlencoded'; | ||
var classCallCheck = function (instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
}; | ||
const URL_ENCODED = 'urlencoded'; | ||
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); | ||
} | ||
} | ||
var FORMATS = ({ | ||
JSON: JSON$1, | ||
FORM_DATA: FORM_DATA, | ||
URL_ENCODED: URL_ENCODED | ||
}); | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
}; | ||
}(); | ||
/** | ||
* Class for handling responses and requests. | ||
*/ | ||
class Api { | ||
/** | ||
* Base api url | ||
*/ | ||
var _extends = Object.assign || function (target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i]; | ||
/** | ||
* Base http headers | ||
*/ | ||
for (var key in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
target[key] = source[key]; | ||
} | ||
} | ||
} | ||
/** | ||
* Base settings for Fetch Request | ||
*/ | ||
return target; | ||
}; | ||
/** | ||
* List of processors that parse response from server. | ||
*/ | ||
var inherits = function (subClass, superClass) { | ||
if (typeof superClass !== "function" && superClass !== null) { | ||
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); | ||
} | ||
/** | ||
* List of formatter you can use to process content of body request. | ||
*/ | ||
subClass.prototype = Object.create(superClass && superClass.prototype, { | ||
constructor: { | ||
value: subClass, | ||
enumerable: false, | ||
writable: true, | ||
configurable: true | ||
/** | ||
* Constructor. | ||
* | ||
* @param apiUrl - Base api url | ||
* @param processors - List of processors that parse response from server. | ||
* @param defaultHeaders - Base settings for Fetch Request | ||
* @param defaultOptions - List of processors that parse response from server. | ||
*/ | ||
constructor(apiUrl, processors, defaultHeaders, defaultOptions) { | ||
if (processors === void 0) { | ||
processors = []; | ||
} | ||
}); | ||
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; | ||
}; | ||
var possibleConstructorReturn = function (self, call) { | ||
if (!self) { | ||
throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); | ||
} | ||
if (defaultHeaders === void 0) { | ||
defaultHeaders = {}; | ||
} | ||
return call && (typeof call === "object" || typeof call === "function") ? call : self; | ||
}; | ||
if (defaultOptions === void 0) { | ||
defaultOptions = {}; | ||
} | ||
/** | ||
* Class for handling responses and requests. | ||
*/ | ||
var Api = function () { | ||
_defineProperty(this, "apiUrl", void 0); | ||
/** | ||
* Constructor. | ||
* | ||
* @param {string} apiUrl - Base api url | ||
* @param {Array<ProcessorAdapter>} processors - List of processors that parse response from server. | ||
* @param {Object} defaultHeaders - Base settings for Fetch Request | ||
* @param {RequestOptions} defaultOptions - List of processors that parse response from server. | ||
*/ | ||
_defineProperty(this, "defaultHeaders", void 0); | ||
_defineProperty(this, "defaultOptions", void 0); | ||
/** | ||
* Base settings for Fetch Request | ||
*/ | ||
_defineProperty(this, "processors", void 0); | ||
/** | ||
* Base api url | ||
*/ | ||
function Api(apiUrl) { | ||
var processors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; | ||
var defaultHeaders = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
var defaultOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; | ||
classCallCheck(this, Api); | ||
this.apiUrl = apiUrl; | ||
this.defaultHeaders = defaultHeaders; | ||
this.defaultOptions = defaultOptions; | ||
this.processors = processors; | ||
} | ||
/** | ||
* Convert data in object to format of Fetch body. | ||
* | ||
* @param data - Data to convert | ||
* @param to - Format to which convert the data. Default is JSON. | ||
* @returns Converted data | ||
* | ||
* @example | ||
* const body = Api.convertData({ a: 'b' }, Api.FORMATS.JSON); | ||
* // output is {"a":"b"} | ||
*/ | ||
this.apiUrl = apiUrl; | ||
this.defaultHeaders = defaultHeaders; | ||
this.defaultOptions = defaultOptions; | ||
this.processors = processors; | ||
static convertData(data, to) { | ||
if (to === void 0) { | ||
to = JSON$1; | ||
} | ||
/** | ||
* Convert data in object to format of Fetch body. | ||
* | ||
* @param {Object} data - Data to convert | ||
* @param {Format} to - Format to which convert the data. Default is JSON. | ||
* @returns {string | FormData} Converted data | ||
* | ||
* @example | ||
* const body = Api.convertData({ a: 'b' }, Api.FORMATS.JSON_FORMAT); | ||
* // output is {"a":"b"} | ||
*/ | ||
if (to === FORM_DATA) { | ||
const formData = new FormData(); | ||
Object.entries(data).forEach((_ref) => { | ||
let key = _ref[0], | ||
value = _ref[1]; | ||
formData.append(key, value); | ||
}); | ||
return formData; | ||
} | ||
if (to === URL_ENCODED) { | ||
return Api.convertParametersToUrl(data).slice(1); | ||
} | ||
/** | ||
* List of formatter you can use to process content of body request. | ||
* | ||
* @type {{JSON_FORMAT: string, FORM_DATA_FORMAT: string}} | ||
*/ | ||
return JSON.stringify(data); | ||
} | ||
/** | ||
* Convert object to url parameters string. | ||
* | ||
* @param parameters - List of parameters | ||
* @returns Encoded string with ? prefix and variables separated by & | ||
* | ||
* @example | ||
* const parameters = Api.convertData({ a: '%b%' }); | ||
* // output is ?a=%25b%25 | ||
*/ | ||
/** | ||
* List of processors that parse response from server. | ||
*/ | ||
static convertParametersToUrl(parameters) { | ||
const keys = Object.keys(parameters); | ||
if (keys.length === 0) { | ||
return ''; | ||
} | ||
/** | ||
* Base http headers | ||
*/ | ||
return `?${keys.map(key => { | ||
return `${key}=${encodeURIComponent(parameters[key])}`; | ||
}).join('&')}`; | ||
} | ||
/** | ||
* Set default headers. | ||
* | ||
* @param headers - HTTP headers | ||
*/ | ||
createClass(Api, [{ | ||
key: 'setDefaultHeaders', | ||
setDefaultHeaders(headers) { | ||
this.defaultHeaders = headers; | ||
} | ||
/** | ||
* Add default HTTP header. | ||
* | ||
* @param name - Name of header | ||
* @param value - Value for header | ||
* @example | ||
* api.setDefaultHeader('content-type', 'application/json'); | ||
*/ | ||
/** | ||
* Set default headers. | ||
* | ||
* @param {Headers} headers - HTTP headers | ||
*/ | ||
value: function setDefaultHeaders(headers) { | ||
this.defaultHeaders = headers; | ||
} | ||
setDefaultHeader(name, value) { | ||
this.defaultHeaders[name] = value; | ||
} | ||
/** | ||
* Remove default header. | ||
* | ||
* @param name - Name of header | ||
*/ | ||
/** | ||
* Add default HTTP header. | ||
* | ||
* @param {string} name - Name of header | ||
* @param {string} value - Value for header | ||
* @example | ||
* api.setDefaultHeader('content-type', 'application/json'); | ||
*/ | ||
}, { | ||
key: 'setDefaultHeader', | ||
value: function setDefaultHeader(name, value) { | ||
this.defaultHeaders[name] = value; | ||
} | ||
removeDefaultHeader(name) { | ||
delete this.defaultHeaders[name]; | ||
} | ||
/** | ||
* Get default headers. | ||
* | ||
* @returns Get Default headers | ||
*/ | ||
/** | ||
* Remove default header. | ||
* | ||
* @param {string} name - Name of header | ||
*/ | ||
}, { | ||
key: 'removeDefaultHeader', | ||
value: function removeDefaultHeader(name) { | ||
delete this.defaultHeaders[name]; | ||
} | ||
getDefaultHeaders() { | ||
return this.defaultHeaders; | ||
} | ||
/** | ||
* Fetch API url. | ||
* | ||
* @protected | ||
* @param request - Fetch request | ||
* @returns Fetch response | ||
*/ | ||
/** | ||
* Get default headers. | ||
* | ||
* @returns {Headers} - Get Default headers | ||
*/ | ||
}, { | ||
key: 'getDefaultHeaders', | ||
value: function getDefaultHeaders() { | ||
return this.defaultHeaders; | ||
} | ||
fetchRequest(request) { | ||
return fetch(request); | ||
} | ||
/** | ||
* Request given API endpoint. | ||
* | ||
* @param namespace - Api endpoint or full url | ||
* @param method - Request method eg. POST or GET | ||
* @param options - Fetch options | ||
* @param headers - Custom headers | ||
* @returns processed response | ||
* @example | ||
* const { data } = await api.request('ad', 'POST', { | ||
* body: '{"ad":1}' | ||
* }) | ||
* | ||
* const { data } = await api.request('http://i-can-request-full-url.com/?a=b', 'GET') | ||
*/ | ||
/** | ||
* Fetch API url. | ||
* | ||
* @protected | ||
* @param {Request} request - Fetch request | ||
* @returns {Promise<Response>} Fetch response | ||
*/ | ||
}, { | ||
key: 'fetchRequest', | ||
value: function fetchRequest(request) { | ||
return fetch(request); | ||
} | ||
request(namespace, method, options, headers) { | ||
if (options === void 0) { | ||
options = {}; | ||
} | ||
/** | ||
* Request given API endpoint. | ||
* | ||
* @param {string} namespace - Api endpoint or full url | ||
* @param {MethodType} method - Request method eg. POST or GET | ||
* @param {RequestOptions} options - Fetch options | ||
* @param {Object} headers - Custom headers | ||
* @returns {Promise<ProcessedResponse>} processed response | ||
* @example | ||
* const { data } = await api.request('ad', 'POST', { | ||
* body: '{"ad":1}' | ||
* }) | ||
* | ||
* const { data } = await api.request('http://i-can-request-full-url.com/?a=b', 'GET') | ||
*/ | ||
if (headers === void 0) { | ||
headers = {}; | ||
} | ||
}, { | ||
key: 'request', | ||
value: function request(namespace, method) { | ||
var _this = this; | ||
const urlToRequest = namespace.indexOf('http') === 0 ? namespace : `${this.apiUrl}/${namespace}`; | ||
const request = new Request(urlToRequest, _objectSpread({}, this.defaultOptions, { | ||
method, | ||
// @ts-ignore | ||
headers: new Headers(_objectSpread({}, this.getDefaultHeaders(), headers)) | ||
}, options)); | ||
return this.fetchRequest(request).then(response => { | ||
return resolveProcessors(response, this.processors, request); | ||
}); | ||
} | ||
/** | ||
* Send a request with body. | ||
* | ||
* @protected | ||
* @param namespace - api endpoint | ||
* @param method - api method | ||
* @param data - body JSON parameters | ||
* @param format - format of body request | ||
* @param headers - custom headers | ||
* @returns processed response | ||
*/ | ||
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
var headers = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; | ||
var urlToRequest = namespace.indexOf('http') === 0 ? namespace : this.apiUrl + '/' + namespace; | ||
requestWithBody(namespace, method, data, format, headers) { | ||
if (headers === void 0) { | ||
headers = {}; | ||
} | ||
var request = new Request(urlToRequest, _extends({}, this.defaultOptions, { | ||
method: method, | ||
headers: new Headers(_extends({}, this.getDefaultHeaders(), headers)) | ||
}, options)); | ||
return this.request(namespace, method, { | ||
body: Api.convertData(data, format) | ||
}, headers); | ||
} | ||
/** | ||
* Send a GET request. | ||
* | ||
* @param namespace - api endpoint | ||
* @param parameters - get parameters | ||
* @param headers - custom headers | ||
* @returns processed response | ||
* | ||
* @example | ||
* const { data } = await api.get('brand', { id: 5 }) | ||
* // will call YOUR_URI/brand?id=5 | ||
* console.log(data); | ||
*/ | ||
return this.fetchRequest(request).then(function (response) { | ||
return resolveProcessors(response, _this.processors, request); | ||
}); | ||
} | ||
/** | ||
* Send a request with body. | ||
* | ||
* @protected | ||
* @param {string} namespace - api endpoint | ||
* @param {MethodType} method - api method | ||
* @param {Object} data - body JSON parameters | ||
* @param {Format} format - format of body request | ||
* @param {Object} headers - custom headers | ||
* @returns {Promise<ProcessedResponse>} processed response | ||
*/ | ||
get(namespace, parameters, headers) { | ||
if (parameters === void 0) { | ||
parameters = {}; | ||
} | ||
}, { | ||
key: 'requestWithBody', | ||
value: function requestWithBody(namespace, method, data, format) { | ||
var headers = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; | ||
if (headers === void 0) { | ||
headers = {}; | ||
} | ||
return this.request(namespace, method, { | ||
body: Api.convertData(data, format) | ||
}, headers); | ||
} | ||
return this.request(`${namespace}${Api.convertParametersToUrl(parameters)}`, 'GET', {}, headers); | ||
} | ||
/** | ||
* Send a POST request. | ||
* | ||
* @param namespace - Api endpoint | ||
* @param data - Request object | ||
* @param format - Format of body request | ||
* @param headers - custom headers | ||
* @returns Processed response | ||
*/ | ||
/** | ||
* Send a GET request. | ||
* | ||
* @param {string} namespace - api endpoint | ||
* @param {Object} parameters - get parameters | ||
* @param {Object} headers - custom headers | ||
* @returns {Promise<ProcessedResponse>} processed response | ||
* | ||
* @example | ||
* const { data } = await api.get('brand', { id: 5 }) | ||
* // will call YOUR_URI/brand?id=5 | ||
* console.log(data); | ||
*/ | ||
}, { | ||
key: 'get', | ||
value: function get$$1(namespace) { | ||
var parameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var headers = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
post(namespace, data, format, headers) { | ||
if (data === void 0) { | ||
data = {}; | ||
} | ||
return this.request('' + namespace + Api.convertParametersToUrl(parameters), 'GET', {}, headers); | ||
} | ||
if (format === void 0) { | ||
format = JSON$1; | ||
} | ||
/** | ||
* Send a POST request. | ||
* | ||
* @param {string} namespace - Api endpoint | ||
* @param {Object} data - Request object | ||
* @param {?Format} format - Format of body request | ||
* @param {Object} headers - custom headers | ||
* @returns {Promise<ProcessedResponse>} Processed response | ||
*/ | ||
if (headers === void 0) { | ||
headers = {}; | ||
} | ||
}, { | ||
key: 'post', | ||
value: function post(namespace) { | ||
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var format = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : JSON_FORMAT; | ||
var headers = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; | ||
return this.requestWithBody(namespace, 'POST', data, format, headers); | ||
} | ||
/** | ||
* Send a PUT request. | ||
* | ||
* @param namespace - Api endpoint | ||
* @param data - Request object | ||
* @param format - Format of body request | ||
* @param headers - custom headers | ||
* @returns Processed response | ||
*/ | ||
return this.requestWithBody(namespace, 'POST', data, format, headers); | ||
} | ||
/** | ||
* Send a PUT request. | ||
* | ||
* @param {string} namespace - Api endpoint | ||
* @param {Object} data - Request object | ||
* @param {?Format} format - Format of body request | ||
* @param {Object} headers - custom headers | ||
* @returns {Promise<ProcessedResponse>} Processed response | ||
*/ | ||
put(namespace, data, format, headers) { | ||
if (data === void 0) { | ||
data = {}; | ||
} | ||
}, { | ||
key: 'put', | ||
value: function put(namespace) { | ||
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var format = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : JSON_FORMAT; | ||
var headers = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; | ||
if (format === void 0) { | ||
format = JSON$1; | ||
} | ||
return this.requestWithBody(namespace, 'PUT', data, format, headers); | ||
} | ||
if (headers === void 0) { | ||
headers = {}; | ||
} | ||
/** | ||
* Send a DELETE request. | ||
* | ||
* @param {string} namespace - Api endpoint | ||
* @param {Object} headers - custom headers | ||
* @returns {Promise<ProcessedResponse>} Processed response | ||
*/ | ||
return this.requestWithBody(namespace, 'PUT', data, format, headers); | ||
} | ||
/** | ||
* Send a DELETE request. | ||
* | ||
* @param namespace - Api endpoint | ||
* @param headers - custom headers | ||
* @returns Processed response | ||
*/ | ||
}, { | ||
key: 'delete', | ||
value: function _delete(namespace) { | ||
var headers = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
return this.request(namespace, 'DELETE', {}, headers); | ||
} | ||
}], [{ | ||
key: 'convertData', | ||
value: function convertData(data) { | ||
var to = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : JSON_FORMAT; | ||
delete(namespace, headers) { | ||
if (headers === void 0) { | ||
headers = {}; | ||
} | ||
if (to === FORM_DATA_FORMAT) { | ||
var formData = new FormData(); | ||
Object.keys(data).forEach(function (key) { | ||
var value = data[key]; | ||
formData.append(key, typeof value === 'number' ? value.toString() : value); | ||
}); | ||
return formData; | ||
} | ||
return this.request(namespace, 'DELETE', {}, headers); | ||
} | ||
if (to === URL_ENCODED_FORMAT) { | ||
return Api.convertParametersToUrl(data).slice(1); | ||
} | ||
} | ||
return JSON.stringify(data); | ||
} | ||
_defineProperty(Api, "FORMATS", FORMATS); | ||
/** | ||
* Convert object to url parameters string. | ||
* | ||
* @param {Object} parameters - List of parameters | ||
* @returns {string} Encoded string with ? prefix and variables separated by & | ||
* | ||
* @example | ||
* const parameters = Api.convertData({ a: '%b%' }); | ||
* // output is ?a=%25b%25 | ||
*/ | ||
/** | ||
* Processor provider that process response from API and throw custom Exception. | ||
*/ | ||
class DefaultResponseProcessor { | ||
/** | ||
* Constructor. | ||
* | ||
* @param Exception - Exception class that will be throwed if request fails. | ||
* @param decoder - Define custom response body decoder. | ||
*/ | ||
constructor(Exception, decoder) { | ||
_defineProperty(this, "Exception", void 0); | ||
}, { | ||
key: 'convertParametersToUrl', | ||
value: function convertParametersToUrl(parameters) { | ||
var keys = Object.keys(parameters); | ||
_defineProperty(this, "decoder", void 0); | ||
if (keys.length === 0) { | ||
return ''; | ||
} | ||
this.Exception = Exception; | ||
this.decoder = decoder || DefaultResponseProcessor.decodeResponse; | ||
} | ||
return '?' + keys.map(function (key) { | ||
var value = parameters[key]; | ||
return key + '=' + encodeURIComponent(typeof value === 'number' ? value.toString() : value); | ||
}).join('&'); | ||
} | ||
}]); | ||
return Api; | ||
}(); | ||
async processResponse(response, request) { | ||
const decodedResponse = await this.decoder(response); | ||
const toRespond = { | ||
data: decodedResponse, | ||
status: response.status, | ||
source: response | ||
}; | ||
Api.FORMATS = { | ||
JSON_FORMAT: JSON_FORMAT, | ||
FORM_DATA_FORMAT: FORM_DATA_FORMAT, | ||
URL_ENCODED_FORMAT: URL_ENCODED_FORMAT | ||
}; | ||
if (!response.ok) { | ||
throw new this.Exception(toRespond, request); | ||
} | ||
/** | ||
* Decode API body response. | ||
* | ||
* @param {Response} response - Native response. | ||
* @returns {DecodedStream} Decoded json or simple string. | ||
*/ | ||
function decodeResponse(response) { | ||
var contentType = response.headers.get('content-type'); | ||
return toRespond; | ||
} | ||
// on default decode response as text | ||
static decodeResponse(response) { | ||
const contentType = response.headers.get('content-type'); // on default decode response as text | ||
if (!contentType) { | ||
return response.text(); | ||
return response.text(); | ||
} | ||
if (contentType.indexOf('json') >= 0) { | ||
return response.json(); | ||
return response.json(); | ||
} | ||
if (contentType.indexOf('text') >= 0 || contentType.indexOf('xml') >= 0) { | ||
return response.text(); | ||
return response.text(); | ||
} | ||
return response.blob(); | ||
} | ||
} | ||
/** | ||
* Process response from API. | ||
* | ||
* @param {Response} response - Native response. | ||
* @param {BodyDecoder} decoder - Custom body decoder. | ||
* @returns {Promise<ProcessedResponse>} Processed response from API. | ||
*/ | ||
function responseProcessor(response) { | ||
var decoder = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : decodeResponse; | ||
return decoder(response).then(function (decodedResponse) { | ||
// create custom response format | ||
var toRespond = { | ||
data: decodedResponse, | ||
status: response.status, | ||
source: response | ||
}; | ||
// response ok means that response was successful (2xx) | ||
if (response.ok) { | ||
return toRespond; | ||
} | ||
// otherwise create an error | ||
throw toRespond; | ||
}); | ||
} | ||
/** | ||
* Processor provider that process response from API and throw custom Exception. | ||
*/ | ||
var DefaultResponseProcessor = function () { | ||
/* eslint-disable no-proto */ | ||
/** | ||
* Constructor. | ||
* | ||
* @param {Class<ApiExceptionInterface>} Exception - Exception class that will be throwed if request fails. | ||
* @param {Function} decoder - Define custom response body decoder. | ||
*/ | ||
function DefaultResponseProcessor(Exception) { | ||
var decoder = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : decodeResponse; | ||
classCallCheck(this, DefaultResponseProcessor); | ||
this.decoder = decodeResponse; | ||
this.Exception = Exception; | ||
this.decoder = decoder; | ||
this.processResponse = this.processResponse.bind(this); | ||
} | ||
/** | ||
* Process response from API. | ||
* | ||
* @param {Response} response - Native fetch response | ||
* @param {Request} request - Native fetch request | ||
* @returns {Promise<ProcessedResponse>} Processed response. | ||
*/ | ||
createClass(DefaultResponseProcessor, [{ | ||
key: 'processResponse', | ||
value: function processResponse(response, request) { | ||
var _this = this; | ||
return responseProcessor(response, this.decoder).catch(function (exception) { | ||
if (exception.data && exception.status && exception.source) { | ||
throw new _this.Exception(exception, request); | ||
} | ||
throw exception; | ||
}); | ||
} | ||
}]); | ||
return DefaultResponseProcessor; | ||
}(); | ||
/** | ||
* Default API Exception | ||
*/ | ||
class DefaultApiException extends Error { | ||
/** | ||
* Response from server that throwed an error. | ||
*/ | ||
/* eslint-disable no-proto */ | ||
var DefaultApiException = function (_Error) { | ||
inherits(DefaultApiException, _Error); | ||
/** | ||
* Request that failed. | ||
*/ | ||
@@ -555,37 +497,33 @@ /** | ||
* | ||
* @param {ProcessedResponse} response - Processed response from server. | ||
* @param {Request} request - Fetch Request. | ||
* @param response - Processed response from server. | ||
* @param request - Fetch Request. | ||
*/ | ||
constructor(response, request) { | ||
super(`Api exception: ${JSON.stringify(response.data)}`); | ||
/** | ||
* Response from server that throwed an error. | ||
*/ | ||
function DefaultApiException(response, request) { | ||
classCallCheck(this, DefaultApiException); | ||
_defineProperty(this, "response", void 0); | ||
var _this = possibleConstructorReturn(this, (DefaultApiException.__proto__ || Object.getPrototypeOf(DefaultApiException)).call(this, 'Api exception: ' + JSON.stringify(response.data))); | ||
_defineProperty(this, "request", void 0); | ||
_this.response = response; | ||
_this.request = request; | ||
this.response = response; | ||
this.request = request; // babel bug - https://github.com/babel/babel/issues/4485 | ||
// @ts-ignore | ||
// babel bug - https://github.com/babel/babel/issues/4485 | ||
// $FlowFixMe | ||
_this.__proto__ = DefaultApiException.prototype; | ||
return _this; | ||
this.__proto__ = DefaultApiException.prototype; | ||
} | ||
/** | ||
* Request that failed. | ||
*/ | ||
getResponse() { | ||
return this.response; | ||
} | ||
getRequest() { | ||
return this.request; | ||
} | ||
return DefaultApiException; | ||
}(Error); | ||
} | ||
exports.JSON_FORMAT = JSON_FORMAT; | ||
exports.FORM_DATA_FORMAT = FORM_DATA_FORMAT; | ||
exports.URL_ENCODED_FORMAT = URL_ENCODED_FORMAT; | ||
// piggy way how to reexport with babel | ||
exports.Api = Api; | ||
exports.defaultResponseProcessor = responseProcessor; | ||
exports.DefaultResponseProcessor = DefaultResponseProcessor; | ||
exports.DefaultApiException = DefaultApiException; |
'use strict'; | ||
// processor can be instance of class | ||
/** | ||
* Resolve given processor. | ||
* | ||
* @param {Input} response - Response to process. | ||
* @param {Array<ProcessorAdapter>} list - Array of processors. | ||
* @param {Request} request - fetch request | ||
* @param {number} i - Index of current processor. | ||
* @returns {any} Processed response | ||
* @param response - Response to process. | ||
* @param list - Array of processors. | ||
* @param request - fetch request | ||
* @param i - Index of current processor. | ||
* @returns Processed response | ||
*/ | ||
async function resolveProcessors(response, list, request, i) { | ||
if (i === void 0) { | ||
i = 0; | ||
} | ||
/** | ||
* @ignore | ||
*/ | ||
function resolveProcessors(response, list, request) { | ||
var i = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; | ||
const processor = list[i]; | ||
var processor = list[i]; | ||
if (!processor) { | ||
return response; | ||
} | ||
if (!processor) { | ||
return Promise.resolve(response); | ||
} | ||
const processedResponse = typeof processor === 'function' ? await processor(response, request) : await processor.processResponse(response, request); | ||
return (typeof processor === 'function' ? processor(response) : processor.processResponse(response, request)).then(function (processedResponse) { | ||
if (list[i + 1]) { | ||
return resolveProcessors(processedResponse, list, request, i + 1); | ||
} | ||
if (list[i + 1]) { | ||
return resolveProcessors(processedResponse, list, request, i + 1); | ||
} | ||
return processedResponse; | ||
}); | ||
return processedResponse; | ||
} | ||
// processor can be function or instance of class | ||
module.exports = resolveProcessors; |
{ | ||
"name": "rest-api-handler", | ||
"version": "1.8.1", | ||
"version": "2.0.0", | ||
"description": "Handler for REST APIs", | ||
"main": "dist/index.js", | ||
"jsnext:main": "dist/index.es.js", | ||
"module": "dist/index.es.js", | ||
"jsnext:main": "dist/index.esm.js", | ||
"module": "dist/index.esm.js", | ||
"types": "dist/index.d.ts", | ||
"repository": { | ||
@@ -24,28 +25,18 @@ "type": "git", | ||
"devDependencies": { | ||
"@socifi/eslint-config": "^1.6.2", | ||
"@socifi/jest-config": "^1.4.0", | ||
"@socifi/rollup-config": "^1.6.0", | ||
"cross-fetch": "^2.2.0", | ||
"flow-bin": "0.75.0", | ||
"flow-coverage-report": "^0.5.0", | ||
"flow-typed": "^2.4.0" | ||
"@socifi/babel-config": "^0.6.0", | ||
"@socifi/eslint-config": "^2.0.1", | ||
"@socifi/jest-config": "^2.0.1", | ||
"@socifi/rollup-config": "^2.0.1", | ||
"cross-fetch": "^2.2.0" | ||
}, | ||
"browserslist": [ | ||
"> 1%", | ||
"Last 2 versions", | ||
"not ie <= 10", | ||
"not ie_mob <= 10" | ||
], | ||
"scripts": { | ||
"lint": "eslint ./src ./test", | ||
"lint-export": "npm run lint -- -o ./tests_results/checkstyle/js-checkstyle.xml -f checkstyle", | ||
"flow": "flow", | ||
"flow-init": "flow-typed install jest@22.x", | ||
"flow-coverage": "flow-coverage-report -f \"node node_modules/flow-bin/vendor/flow\" -i \"./src/**/*.js*\" -t html -t text -t json -o tests_results/coverage/flow", | ||
"lint": "eslint --ext .ts ./src ./tests", | ||
"lint:export": "npm run lint -- -o ./tests_results/checkstyle/js-checkstyle.xml -f checkstyle", | ||
"tsc": "tsc", | ||
"test": "jest", | ||
"test-build": "npm run test -- --config jest.config.build.js", | ||
"build": "rm -rf ./dist && rollup --config ./rollup.config.js", | ||
"test-all": "npm run lint && npm run flow && npm run flow-coverage && npm run test", | ||
"prepublishOnly": "npm run build && npm run test-build" | ||
"test:build": "npm run test -- --config jest.config.build.js", | ||
"build": "rollup --config ./rollup.config.js", | ||
"test:all": "npm run lint && npm run tsc && npm run test", | ||
"prepublishOnly": "npm run build && npm run tsc && npm run test:build" | ||
} | ||
} |
@@ -39,6 +39,6 @@ # REST API Handler | ||
```javascript | ||
import { Api, defaultResponseProcessor } from 'rest-api-handler'; | ||
import { Api, defaultResponseProcessor, DefaultApiException } from 'rest-api-handler'; | ||
const api = new Api('https://api.blockcypher.com', [ | ||
defaultResponseProcessor, | ||
new DefaultResponseProcessor(DefaultApiException), | ||
]); | ||
@@ -58,3 +58,3 @@ | ||
const api = new Api('//some.api.com', [ | ||
defaultResponseProcessor, | ||
new DefaultResponseProcessor(DefaultApiException), | ||
onlyDataProcessor, | ||
@@ -97,3 +97,3 @@ ]); | ||
```javascript | ||
import { Api, defaultResponseProcessor, FORM_DATA_FORMAT } from 'rest-api-handler'; | ||
import { Api } from 'rest-api-handler'; | ||
const api = new Api('//some.api.com'); | ||
@@ -103,3 +103,3 @@ | ||
file: fileObject, | ||
}, FORM_DATA_FORMAT); | ||
}, Api.FORMATS.FORM_DATA); | ||
@@ -143,5 +143,5 @@ ``` | ||
const { Api, defaultResponseProcessor } = require('rest-api-handler'); | ||
const { Api, DefaultResponseProcessor, DefaultApiException } = require('rest-api-handler'); | ||
const api = new Api('https://api.blockcypher.com', [ defaultResponseProcessor ]); | ||
const api = new Api('https://api.blockcypher.com', [ new DefaultResponseProcessor(DefaultApiException), ]); | ||
@@ -148,0 +148,0 @@ api.get('v1/btc/main').then((response) => { |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
5
2506
92036
5