UNPKG

@qrvey/fetch

Version:

![install size](https://packagephobia.now.sh/badge?p=%40qrvey%2Ffetch) ![coverage](https://img.shields.io/badge/unit_test_coverage-96%25-brightgreen)

263 lines (255 loc) 9.01 kB
'use strict'; var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __objRest = (source, exclude) => { var target = {}; for (var prop in source) if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0) target[prop] = source[prop]; if (source != null && __getOwnPropSymbols) for (var prop of __getOwnPropSymbols(source)) { if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop)) target[prop] = source[prop]; } return target; }; // src/helpers/constants.ts var HTTPAction = { GET: "GET", POST: "POST", PATCH: "PATCH", DELETE: "DELETE", PUT: "PUT" }; // src/helpers/errors/customError.ts var CustomError = class extends Error { constructor(message, errorDetails, stack, context = process.env.SERVICE_NAME || "QrveyCustomError") { super(message); this.errorDetails = errorDetails; this.context = context; this.name = "ERROR in " + this.context; this.stack = stack; } toJSON() { return { name: this.name, message: this.message, stack: this.stack, details: this.errorDetails }; } }; // src/helpers/errors/restClientError.ts var RestClientError = class extends CustomError { // eslint-disable-next-line @typescript-eslint/no-explicit-any constructor(url, restError = {}) { const message = `REST Client Error at ${url}${(restError == null ? void 0 : restError.message) ? `: ${restError == null ? void 0 : restError.message}` : ""}`; super(message, restError, restError.stack); } }; // src/helpers/errors/restBadHttpActionParams.ts var RestBadHttpActionParams = class extends CustomError { // eslint-disable-next-line @typescript-eslint/no-explicit-any constructor(url, message, error = {}) { const errorMessage = `Bad RestHttpAction params at ${url}: ${message}`; super(errorMessage, error.message || error, error.stack); } }; // src/services/fetchClient.service.ts var FetchClientService = class { static validateEndpoint(endpoint) { if (endpoint.startsWith("/")) return; const errorMessage = `Invalid endpoint "${endpoint}". Please replace with "/${endpoint}"`; throw new RestBadHttpActionParams(endpoint, errorMessage); } static buildUrl(endpoint, options) { var _a, _b; const baseDomain = (_a = process.env.DOMAIN) != null ? _a : ""; const privateDomain = (_b = process.env.PRIVATE_DOMAIN) != null ? _b : ""; const defaultDomain = options.privateDomain === false ? baseDomain : privateDomain; return `${options.baseDomain || defaultDomain}${endpoint}`; } static baseHeaders(options) { var _a, _b; const baseHeaders = { "Content-Type": "application/json" }; const customContentTypeHeader = ((_a = options.headers) == null ? void 0 : _a["content-type"]) || ((_b = options.headers) == null ? void 0 : _b["Content-Type"]); if (customContentTypeHeader) { baseHeaders["Content-Type"] = customContentTypeHeader; } if (options.useApiKey && process.env.API_KEY) baseHeaders["x-api-key"] = process.env.API_KEY; return baseHeaders; } static customHeaders(options) { const _a = options.headers || {}, { // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars "Content-Type": _ContentType, // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars "content-type": _contentType } = _a, customHeadersObject = __objRest(_a, [ "Content-Type", "content-type" ]); return customHeadersObject; } static buildFetchOptions(method, body, options) { const headers = __spreadValues(__spreadValues({}, this.baseHeaders(options)), this.customHeaders(options)); const filteredHeaders = Object.fromEntries( Object.entries(headers).filter( ([, value]) => value !== null && value !== void 0 ) ); const requestOptions = { headers: filteredHeaders, method }; if (body) requestOptions["body"] = JSON.stringify(body); return requestOptions; } static isValidUrl(url) { return !!(url.protocol && url.hostname && url.pathname); } static hasValidProtocol(url) { const secureProtocols = ["http:", "https:"]; return secureProtocols.includes(url.protocol); } static verifyUrl(urlObj) { if (!this.isValidUrl(urlObj)) { throw new RestBadHttpActionParams( "Invalid URL", `URL details: Protocol: ${urlObj.protocol}, Hostname: ${urlObj.hostname}, Pathname: ${urlObj.pathname}` ); } if (!this.hasValidProtocol(urlObj)) { throw new RestBadHttpActionParams( "Invalid URL", `URL protocol [${urlObj.protocol}] is not secure` ); } } static toHttpUrl(url) { try { const urlObj = new URL(url); this.verifyUrl(urlObj); return urlObj.href; } catch (error) { throw new RestBadHttpActionParams( `Invalid URL [${url}]`, "URL is not valid.", error ); } } static async getResponseData(isJsonResponse, response) { const clonedResponse = response.clone(); let responseData = null; try { if (isJsonResponse) { responseData = await response.json(); } else { responseData = await response.text(); } await clonedResponse.text(); } catch (_) { responseData = await clonedResponse.text(); } return responseData; } static async handleResponse(response) { const responseContentType = response.headers.get("content-type"); const isJsonResponse = responseContentType && responseContentType.includes("application/json"); const responseData = await this.getResponseData( !!isJsonResponse, response ); if (response.ok) { return responseData; } throw new RestClientError(response.url, responseData); } static fetchData(url, requestOptions) { return fetch(url, requestOptions).then(this.handleResponse.bind(this)).catch((error) => { if (error instanceof RestClientError) throw error; throw new RestClientError(url, error); }); } static queryParamsToQueryString(queryParameters) { const queryParamsArray = Object.entries(queryParameters).map( ([queryName, queryValue]) => { const isArrayValue = Array.isArray(queryValue); if (isArrayValue) return queryValue.map((val) => `${queryName}=${val}`).join("&"); else return `${queryName}=${queryValue}`; } ); return queryParamsArray.join("&"); } static httpAction(method, endpoint, body, options = {}) { this.validateEndpoint(endpoint); const url = this.buildUrl(endpoint, options); const queryParamsString = options.queryParameters ? `?${this.queryParamsToQueryString(options.queryParameters)}` : ""; const httpUrl = this.toHttpUrl(`${url}${queryParamsString}`); return this.fetchData( httpUrl, this.buildFetchOptions(method.toUpperCase(), body, options) ); } }; // src/services/fetch.service.ts var FetchService = class _FetchService { static sendRequest(endpoint, body, options) { return FetchClientService.httpAction( options.method, endpoint, body, options ); } static get(endpoint, options) { return _FetchService.sendRequest(endpoint, null, __spreadProps(__spreadValues({}, options), { method: HTTPAction.GET })); } static post(endpoint, body, options) { return _FetchService.sendRequest(endpoint, body, __spreadProps(__spreadValues({}, options), { method: HTTPAction.POST })); } static put(endpoint, body, options) { return _FetchService.sendRequest(endpoint, body, __spreadProps(__spreadValues({}, options), { method: HTTPAction.PUT })); } static patch(endpoint, body, options) { return _FetchService.sendRequest(endpoint, body, __spreadProps(__spreadValues({}, options), { method: HTTPAction.PATCH })); } static delete(endpoint, body, options) { return _FetchService.sendRequest(endpoint, body, __spreadProps(__spreadValues({}, options), { method: HTTPAction.DELETE })); } }; exports.FetchService = FetchService; //# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map