@qrvey/fetch
Version:
 
340 lines (332 loc) • 12.2 kB
JavaScript
;
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 = {}, status) {
const message = `REST Client Error at ${url}${(restError == null ? void 0 : restError.message) ? `: ${restError == null ? void 0 : restError.message}` : ""}`;
super(message, restError, restError.stack);
if (status !== void 0) this.status = status;
}
};
// 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, _c, _d;
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;
const serviceNameEnv = (_c = process.env.SERVICE_NAME) == null ? void 0 : _c.trim();
const hostnameEnv = (_d = process.env.HOSTNAME) == null ? void 0 : _d.trim();
if (!baseHeaders["q-service-name"] && (serviceNameEnv == null ? void 0 : serviceNameEnv.length)) {
baseHeaders["q-service-name"] = serviceNameEnv;
}
if (!baseHeaders["q-hostname"] && (hostnameEnv == null ? void 0 : hostnameEnv.length)) {
baseHeaders["q-hostname"] = hostnameEnv;
}
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 internalHeaders() {
var _a, _b;
const internalHeaders = {};
const serviceNameEnv = (_a = process.env.SERVICE_NAME) == null ? void 0 : _a.trim();
const hostnameEnv = (_b = process.env.HOSTNAME) == null ? void 0 : _b.trim();
if (serviceNameEnv == null ? void 0 : serviceNameEnv.length) {
internalHeaders["q-service-name"] = serviceNameEnv;
}
if (hostnameEnv == null ? void 0 : hostnameEnv.length) {
internalHeaders["q-hostname"] = hostnameEnv;
}
return internalHeaders;
}
static buildFetchOptions(method, body, options) {
const headers = __spreadValues(__spreadValues(__spreadValues({}, this.baseHeaders(options)), this.customHeaders(options)), this.internalHeaders());
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 isFileDownload(contentType, contentDisposition) {
return (contentDisposition == null ? void 0 : contentDisposition.includes("attachment")) || (contentType == null ? void 0 : contentType.includes("application/octet-stream")) || (contentType == null ? void 0 : contentType.includes("text/csv")) || (contentType == null ? void 0 : contentType.includes("application/vnd.ms-excel")) || (contentType == null ? void 0 : contentType.includes("application/vnd.openxmlformats")) || (contentType == null ? void 0 : contentType.includes("application/zip")) || (contentType == null ? void 0 : contentType.includes("application/pdf"));
}
static async getResponseData(isJsonResponse, response, options) {
try {
if (options.returnRawResponse) {
return response;
}
const contentType = response.headers.get("content-type");
const contentDisposition = response.headers.get(
"content-disposition"
);
const contentEncoding = response.headers.get("content-encoding");
const isFileDownload = this.isFileDownload(
contentType,
contentDisposition
);
if (options.skipJsonParsing && contentEncoding) {
return await response.arrayBuffer();
}
if (options.skipJsonParsing && isFileDownload) {
return await response.arrayBuffer();
}
if (options.skipJsonParsing) {
return await response.text();
}
const text = await response.text();
if (isJsonResponse) {
try {
return JSON.parse(text);
} catch (e) {
return text;
}
}
return text;
} catch (error) {
console.error("Error processing response data:", error);
return null;
}
}
static getResponseHeaders(response) {
const headers = {};
response.headers.forEach((value, key) => {
headers[key] = value;
});
return headers;
}
static async handleResponse(response, httpActionOptions) {
const responseContentType = response.headers.get("content-type");
const isJsonResponse = responseContentType && responseContentType.includes("application/json") && !httpActionOptions.skipJsonParsing;
const responseData = await this.getResponseData(
!!isJsonResponse,
response,
httpActionOptions
);
if (response.ok) {
if (httpActionOptions.includeHttpResponseDetails) {
const headers = this.getResponseHeaders(response);
return {
status: response.status,
data: responseData,
headers
};
}
return responseData;
}
throw new RestClientError(
response.url,
responseData != null ? responseData : {},
response.status
);
}
static fetchData(url, {
fetchOptions,
httpActionOptions
}) {
return fetch(url, fetchOptions).then(
(response) => this.handleResponse(response, httpActionOptions)
).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}`);
const fetchDataOptions = {
fetchOptions: this.buildFetchOptions(
method.toUpperCase(),
body,
options
),
httpActionOptions: options
};
return this.fetchData(httpUrl, fetchDataOptions);
}
};
// 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