Comparing version 0.3.1 to 0.4.0
@@ -6,2 +6,10 @@ All notable changes to this project will be documented in this file. | ||
## [0.4.0] - 2019-05-09 | ||
### Changed | ||
- throwing Timeout error on timeout instead of Aborted error | ||
### Added | ||
- a lot of documentation | ||
### Fixed | ||
- Vulnerable libraries (upgraded versions in lockfile) | ||
## [0.3.1] - 2019-04-02 | ||
@@ -8,0 +16,0 @@ ### Fixed |
@@ -14,13 +14,70 @@ "use strict"; | ||
/** | ||
* Base/generic error type | ||
* | ||
* @class Error | ||
* @property {string} message - error message | ||
* @property {Object} details - error details | ||
* @property {string} stack - stack trace | ||
*/ | ||
/** | ||
* Non-success response custom error | ||
* | ||
* @class HttpError | ||
* @extends Error | ||
*/ | ||
const HttpError = createError("HttpError"); | ||
/** | ||
* Response 4xx error | ||
* | ||
* @class ClientHttpError | ||
* @extends HttpError | ||
* @extends Error | ||
*/ | ||
exports.HttpError = HttpError; | ||
const ClientHttpError = createError("ClientHttpError", HttpError); | ||
/** | ||
* Response 5xx error | ||
* | ||
* @class ServerHttpError | ||
* @extends HttpError | ||
* @extends Error | ||
*/ | ||
exports.ClientHttpError = ClientHttpError; | ||
const ServerHttpError = createError("ServerHttpError", HttpError); | ||
/** | ||
* Response timeout error | ||
* | ||
* @class TimeoutHttpError | ||
* @extends ServerHttpError | ||
* @extends HttpError | ||
* @extends Error | ||
*/ | ||
exports.ServerHttpError = ServerHttpError; | ||
const TimeoutHttpError = createError("TimeoutHttpError", ServerHttpError); | ||
/** | ||
* Response aborted error | ||
* | ||
* @class AbortedHttpError | ||
* @extends ServerHttpError | ||
* @extends HttpError | ||
* @extends Error | ||
*/ | ||
exports.TimeoutHttpError = TimeoutHttpError; | ||
const AbortedHttpError = createError("AbortedHttpError", ClientHttpError); | ||
/** | ||
* Response data type was different than expected | ||
* | ||
* @class ResponseDataTypeMismatchError | ||
* @extends Error | ||
*/ | ||
exports.AbortedHttpError = AbortedHttpError; | ||
const ResponseDataTypeMismatchError = createError("ResponseDataTypeMismatchError"); | ||
exports.ResponseDataTypeMismatchError = ResponseDataTypeMismatchError; |
@@ -38,2 +38,11 @@ "use strict"; | ||
* @property {string} type - expected data type | ||
* @property {Object} headers - headers to be send with each request | ||
* @property {number} retry - how many times should request try to get a successful response. Can be overridden with | ||
* retryPolicy. 1 = no retry, 2 = one retry, etc. | ||
* @property {number} retryInterval - time between retries. Can be overriden with retryWaitPolicy | ||
* @property {function} retryPolicy - function that decides if request should be retried | ||
* @property {function} retryWaitPolicy - function that decides how much time to wait before next retry | ||
* @property {number} timeout - timeout for each request | ||
* @property {number} totalTimeout - total timeout in which all, including retried requests should be fulfilled | ||
* (this includes wait time between, so timeout=100, wait=200, totalTimeout=350 means that retry will have only 50ms) | ||
*/ | ||
@@ -87,10 +96,22 @@ const contentTypeMap = { | ||
const noop = () => undefined; | ||
/** | ||
* @class ApiClient | ||
*/ | ||
const createAbortError = ({ | ||
isTimeouted, | ||
isGlobalTimeouted, | ||
lastError, | ||
errorDetails | ||
}) => { | ||
const useTimeoutError = isTimeouted || isGlobalTimeouted; | ||
if (useTimeoutError) { | ||
return new _errors.TimeoutHttpError(`Request aborted because of timeout`, lastError, errorDetails); | ||
} | ||
return new _errors.AbortedHttpError(`Request aborted`, lastError, errorDetails); | ||
}; | ||
class ApiClient { | ||
/** | ||
* @param {ApiOptions} options | ||
* @class ApiClient | ||
* @param {ApiOptions} options - options that will override defaults | ||
*/ | ||
@@ -182,23 +203,108 @@ constructor(options) { | ||
const appendChar = hasQS ? "&" : "?"; // @todo extract existing query params from string and include for stringify ? | ||
// @todo add support for string query params | ||
return url + appendChar + stringify(queryParams); | ||
} | ||
/** | ||
* Sends a GET request | ||
* | ||
* @param {string} url - absolute url or relative that will be joined with base url | ||
* @param {Object|null} [queryParams] - query params that will be added to `url` | ||
* @param {ApiOptions} [options] - options that will override defaults and options specified in the constructor | ||
* @returns {Promise<Response>} | ||
* @throws {ClientHttpError} | ||
* @throws {ServerHttpError} | ||
* @throws {ResponseDataTypeMismatchError} | ||
* @throws {AbortedHttpError} | ||
* @throws {TimeoutHttpError} | ||
* @throws {Error} | ||
*/ | ||
get(url, queryParams, options) { | ||
return this.request("GET", url, queryParams, null, options); | ||
} | ||
/** | ||
* Sends a POST request | ||
* | ||
* @param {string} url - absolute url or relative that will be joined with base url | ||
* @param {Object|null} [queryParams] - query params that will be added to `url` | ||
* @param {string|Object} [body] - request body. Used as-is when string or stringified according to given data | ||
* `type` when Object | ||
* @param {ApiOptions} [options] - options that will override defaults and options specified in the constructor | ||
* @returns {Promise<Response>} | ||
* @throws {ClientHttpError} | ||
* @throws {ServerHttpError} | ||
* @throws {ResponseDataTypeMismatchError} | ||
* @throws {AbortedHttpError} | ||
* @throws {TimeoutHttpError} | ||
* @throws {Error} | ||
*/ | ||
post(url, queryParams, body, options) { | ||
return this.request("POST", url, queryParams, body, options); | ||
} | ||
/** | ||
* Sends a PATCH request | ||
* | ||
* @param {string} url - absolute url or relative that will be joined with base url | ||
* @param {Object|null} [queryParams] - query params that will be added to `url` | ||
* @param {string|Object} [body] - request body. Used as-is when string or stringified according to given data | ||
* `type` when Object | ||
* @param {ApiOptions} [options] - options that will override defaults and options specified in the constructor | ||
* @returns {Promise<Response>} | ||
* @throws {ClientHttpError} | ||
* @throws {ServerHttpError} | ||
* @throws {ResponseDataTypeMismatchError} | ||
* @throws {AbortedHttpError} | ||
* @throws {TimeoutHttpError} | ||
* @throws {Error} | ||
*/ | ||
patch(url, queryParams, body, options) { | ||
return this.request("PATCH", url, queryParams, body, options); | ||
} | ||
/** | ||
* Sends a DELETE request | ||
* | ||
* @param {string} url - absolute url or relative that will be joined with base url | ||
* @param {Object|null} [queryParams] - query params that will be added to `url` | ||
* @param {string|Object} [body] - request body. Used as-is when string or stringified according to given data | ||
* `type` when Object | ||
* @param {ApiOptions} [options] - options that will override defaults and options specified in the constructor | ||
* @returns {Promise<Response>} | ||
* @throws {ClientHttpError} | ||
* @throws {ServerHttpError} | ||
* @throws {ResponseDataTypeMismatchError} | ||
* @throws {AbortedHttpError} | ||
* @throws {TimeoutHttpError} | ||
* @throws {Error} | ||
*/ | ||
delete(url, queryParams, body, options) { | ||
return this.request("DELETE", url, queryParams, body, options); | ||
} | ||
/** | ||
* Sends a custom method request | ||
* | ||
* @param {string} method - method to use | ||
* @param {string} url - absolute url or relative that will be joined with base url | ||
* @param {Object|null} [queryParams] - query params that will be added to `url` | ||
* @param {string|Object} [body] - request body. Used as-is when string or stringified according to given data | ||
* `type` when Object | ||
* @param {ApiOptions} [options] - options that will override defaults and options specified in the constructor | ||
* @returns {Promise<Response>} | ||
* @throws {ClientHttpError} | ||
* @throws {ServerHttpError} | ||
* @throws {ResponseDataTypeMismatchError} | ||
* @throws {AbortedHttpError} | ||
* @throws {TimeoutHttpError} | ||
* @throws {Error} | ||
*/ | ||
request(method, originalUrl, queryParams, body, options = {}) { | ||
request(method, url, queryParams, body, options = {}) { | ||
// eslint-disable-line max-lines-per-function | ||
@@ -257,4 +363,8 @@ const start = Date.now(); | ||
}; | ||
const msg = `Request aborted ` + JSON.stringify(errorDetails); | ||
lastError = new _errors.AbortedHttpError(msg, lastError, errorDetails); | ||
lastError = createAbortError({ | ||
isTimeouted, | ||
isGlobalTimeouted, | ||
lastError, | ||
errorDetails | ||
}); | ||
break; | ||
@@ -264,3 +374,3 @@ } | ||
singleTimeout.start(); | ||
return await this._request(method, originalUrl, queryParams, body, fineOptions, currentController.signal); | ||
return await this._request(method, url, queryParams, fineOptions, currentController.signal); | ||
} catch (e) { | ||
@@ -274,4 +384,8 @@ if (e.name === "AbortError") { | ||
}; | ||
const msg = `Request aborted ` + JSON.stringify(errorDetails); | ||
lastError = new _errors.AbortedHttpError(msg, lastError, errorDetails); // it should not try again if: | ||
lastError = createAbortError({ | ||
isTimeouted, | ||
isGlobalTimeouted, | ||
lastError, | ||
errorDetails | ||
}); // it should not try again if: | ||
// globally timeouted | ||
@@ -313,3 +427,3 @@ // aborted by user (abort didn't happened via timeout) | ||
async _request(method, originalUrl, queryParams, body, options, signal) { | ||
async _request(method, originalUrl, queryParams, options, signal) { | ||
const fetchOptions = { ...options, | ||
@@ -353,3 +467,10 @@ method: method.toUpperCase() | ||
} | ||
/** | ||
* Sets global ApiClient configuration that is shared between instances | ||
* | ||
* @param {Object} options | ||
* @param {function} options.URL - `URL`-compatible URL parser, see: https://is.gd/Wbyu4k and https://is.gd/FziUWo | ||
*/ | ||
ApiClient.configure = options => { | ||
@@ -356,0 +477,0 @@ URLParser = options.URL; |
@@ -8,2 +8,9 @@ "use strict"; | ||
/** | ||
* @class Request | ||
* @property {string} url - parsed URL | ||
* @property {Object} queryParams - given query params | ||
* @property {string} originalUrl - original URL as was given | ||
* @property {Object} options - merged options (for `fetch`) that was given for the request | ||
*/ | ||
class Request { | ||
@@ -10,0 +17,0 @@ constructor(url, options, originalUrl, queryParams) { |
@@ -14,2 +14,12 @@ "use strict"; | ||
/** | ||
* @class Response | ||
* @property {number} status - response status | ||
* @property {string} statusText - response status text | ||
* @property {Object} headers - response headers | ||
* @property {Request} request - request that was send | ||
* @property {Object|string} body - response body | ||
* @property {string} type - response type | ||
* @property {Object|string} [rawBody] - response body as string, when it couldn't be decoded from expected JSON | ||
*/ | ||
class Response { | ||
@@ -16,0 +26,0 @@ constructor(result, data, request) { |
@@ -28,2 +28,3 @@ "use strict"; | ||
[TYPE_CLIENT_ERROR]: status => status >= 400 && status < 499, | ||
// 499 is intentional here | ||
[TYPE_SERVER_ERROR]: status => status >= 500 && status < 600 | ||
@@ -30,0 +31,0 @@ }; |
{ | ||
"name": "api-reach", | ||
"version": "0.3.1", | ||
"version": "0.4.0", | ||
"repository": "https://github.com/dzek69/api-reach.git", | ||
@@ -10,3 +10,3 @@ "author": "Jacek Nowacki @dzek69 <git-public@dzek.eu>", | ||
"test": "cross-env NODE_ENV=testing mocha 'src/**/*.spec.js'", | ||
"docs": "node build-scripts/docs && jsdoc src README.md -t node_modules/docdash -d ./docs -u ./tutorials && node build-scripts/docs.after", | ||
"docs": "node build-scripts/docs && jsdoc -r src README.md -t node_modules/docdash -d ./docs -u ./tutorials -c jsdoc.json && node build-scripts/docs.after", | ||
"transpile": "node build-scripts/transpile && babel src -d dist --ignore spec.js", | ||
@@ -13,0 +13,0 @@ "prepublishOnly": "npm run test && npm run lint && npm run docs", |
@@ -13,3 +13,2 @@ # api-reach | ||
- timeout support | ||
- add cache support | ||
@@ -16,0 +15,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
297178
46
2300
38