@qrvey/fetch
Advanced tools
Comparing version 1.0.0 to 1.0.1
'use strict'; | ||
var O=Object.defineProperty,P=Object.defineProperties;var T=Object.getOwnPropertyDescriptors;var m=Object.getOwnPropertySymbols;var f=Object.prototype.hasOwnProperty,I=Object.prototype.propertyIsEnumerable;var A=(s,t,e)=>t in s?O(s,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):s[t]=e,i=(s,t)=>{for(var e in t||(t={}))f.call(t,e)&&A(s,e,t[e]);if(m)for(var e of m(t))I.call(t,e)&&A(s,e,t[e]);return s},p=(s,t)=>P(s,T(t));var y=(s,t)=>{var e={};for(var r in s)f.call(s,r)&&t.indexOf(r)<0&&(e[r]=s[r]);if(s!=null&&m)for(var r of m(s))t.indexOf(r)<0&&I.call(s,r)&&(e[r]=s[r]);return e};var h={GET:"get",POST:"post",PATCH:"patch",DELETE:"delete",PUT:"put"};var a=class extends Error{constructor(t,e){super(`Bad RestHttpAction params at ${t}: ${e}`),this.name="RestBadHttpActionParams";}},d=class extends Error{constructor(t,e){super(`REST Client Error at ${t}: ${e}`),this.name="RestClientError";}};var u=class{static validateEndpoint(t){if(t.startsWith("/"))return;let e=`Invalid endpoint "${t}". Please replace with "/${t}"`;throw new a(t,e)}static buildUrl(t,e){var n;let r=(n=process.env.DOMAIN)!=null?n:"";return `${e.baseDomain||r}${t}`}static baseHeaders(t){var n,o;let e={"Content-Type":"application/json"},r=((n=t.headers)==null?void 0:n["content-type"])||((o=t.headers)==null?void 0:o["Content-Type"]);return r&&(e["Content-Type"]=r),t.useApiKey&&process.env.API_KEY&&(e["x-api-key"]=process.env.API_KEY),e}static customHeaders(t){let o=t.headers||{};return y(o,["Content-Type","content-type"])}static buildFetchOptions(t,e,r){let n=i(i({},this.baseHeaders(r)),this.customHeaders(r)),c={headers:Object.fromEntries(Object.entries(n).filter(([,l])=>l!=null)),method:t};return e&&(c.body=JSON.stringify(e)),c}static isValidUrl(t){return !!(t.protocol&&t.hostname&&t.pathname)}static hasValidProtocol(t){return ["http:","https:"].includes(t.protocol)}static verifyUrl(t){if(!this.isValidUrl(t))throw new a("Invalid URL",`URL details: Protocol: ${t.protocol}, Hostname: ${t.hostname}, Pathname: ${t.pathname}`);if(!this.hasValidProtocol(t))throw new a("Invalid URL",`URL protocol [${t.protocol}] is not secure`)}static toHttpUrl(t){try{let e=new URL(t);return this.verifyUrl(e),e.href}catch(e){throw new a(`Invalid URL [${t}]`,"URL is not valid.")}}static async handleResponse(t){if(t.ok)return t.json();let e=await t.text();throw new d(t.url,e)}static fetchData(t,e){return fetch(t,e).then(this.handleResponse).catch(r=>{throw new d(t,r)})}static queryParamsToQueryString(t){return Object.entries(t).map(([r,n])=>Array.isArray(n)?n.map(c=>`${r}=${c}`).join("&"):`${r}=${n}`).join("&")}static httpAction(t,e,r,n={}){this.validateEndpoint(e);let o=this.buildUrl(e,n),c=n.queryParameters?`?${this.queryParamsToQueryString(n.queryParameters)}`:"",l=this.toHttpUrl(`${o}${c}`);return this.fetchData(l,this.buildFetchOptions(t,r,n))}};var H=class s{static sendRequest(t,e,r){return u.httpAction(r.method,t,e,r)}static get(t,e){return s.sendRequest(t,null,p(i({},e),{method:h.GET}))}static post(t,e,r){return s.sendRequest(t,e,p(i({},r),{method:h.POST}))}static put(t,e,r){return s.sendRequest(t,e,p(i({},r),{method:h.PUT}))}static patch(t,e,r){return s.sendRequest(t,e,p(i({},r),{method:h.PATCH}))}static delete(t,e,r){return s.sendRequest(t,e,p(i({},r),{method:h.DELETE}))}}; | ||
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; | ||
}; | ||
exports.AbstractFetchService = H; | ||
// src/helpers/constants.ts | ||
var HTTPAction = { | ||
GET: "get", | ||
POST: "post", | ||
PATCH: "patch", | ||
DELETE: "delete", | ||
PUT: "put" | ||
}; | ||
// src/helpers/errors.ts | ||
var RestBadHttpActionParams = class extends Error { | ||
constructor(url, message) { | ||
super(`Bad RestHttpAction params at ${url}: ${message}`); | ||
this.name = "RestBadHttpActionParams"; | ||
} | ||
}; | ||
var RestClientError = class extends Error { | ||
constructor(url, message) { | ||
super(`REST Client Error at ${url}: ${message}`); | ||
this.name = "RestClientError"; | ||
} | ||
}; | ||
// 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; | ||
const baseDomain = (_a = process.env.DOMAIN) != null ? _a : ""; | ||
return `${options.baseDomain || baseDomain}${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 || {}, 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." | ||
); | ||
} | ||
} | ||
static async handleResponse(response) { | ||
if (response.ok) | ||
return response.json(); | ||
const responseText = await response.text(); | ||
throw new RestClientError(response.url, responseText); | ||
} | ||
static fetchData(url, requestOptions) { | ||
return fetch(url, requestOptions).then(this.handleResponse).catch((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, 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=out.js.map | ||
//# sourceMappingURL=index.js.map |
@@ -20,3 +20,3 @@ interface IRequestHeaders { | ||
declare class AbstractFetchService { | ||
declare class FetchService { | ||
static sendRequest(endpoint: string, body: unknown, options: IFetchOptions): Promise<unknown>; | ||
@@ -30,2 +30,2 @@ static get(endpoint: string, options: IHttpActionOptions): Promise<unknown>; | ||
export { AbstractFetchService }; | ||
export { FetchService }; |
@@ -5,3 +5,3 @@ { | ||
"main": "dist/cjs/index.js", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"license": "MIT", | ||
@@ -21,3 +21,3 @@ "publishConfig": { | ||
"test": "jest", | ||
"test:cov": "jest --coverage", | ||
"test:cov": "jest --coverage && chmod +x ./coverageReader.sh && sh ./coverageReader.sh", | ||
"type-check": "tsc", | ||
@@ -30,4 +30,4 @@ "build:clean": "rm -rf dist", | ||
"build:compile": "yarn build:compile:cjs && yarn build:compile:esm && yarn build:compile:types", | ||
"build": "yarn build:clean && yarn build:compile", | ||
"publish-package": "yarn build && npm publish" | ||
"build": "yarn test && yarn build:clean && yarn build:compile", | ||
"publish-package": "yarn test:cov && yarn build && npm publish" | ||
}, | ||
@@ -37,2 +37,3 @@ "devDependencies": { | ||
"jest": "^29.7.0", | ||
"lcov-parse": "^1.0.0", | ||
"ts-jest": "^29.1.2", | ||
@@ -39,0 +40,0 @@ "tsup": "^8.0.1", |
# @qrvey/fetch | ||
<div align="center"> | ||
<a href="https://packagephobia.now.sh/result?p=%40qrvey%2Ffetch"> | ||
<img src="https://packagephobia.now.sh/badge?p=%40qrvey%2Ffetch" alt="install size" /> | ||
</a> | ||
</div> | ||
![install size](https://packagephobia.now.sh/badge?p=%40qrvey%2Ffetch) | ||
![coverage](https://img.shields.io/badge/unit_test_coverage-97%25-brightgreen) | ||
@@ -35,5 +32,5 @@ **@qrvey/fetch** is a lightweight and reliable library for making RESTful requests in Node.js applications. It uses the native `fetch` library (Node.js 18+), avoiding the need for external dependencies. | ||
```js | ||
const { AbstractFetchService } = require('@qrvey/fetch'); | ||
const { FetchService } = require('@qrvey/fetch'); | ||
class MyFetchClient extends AbstractFetchService { | ||
class MyFetchClient extends FetchService { | ||
/** | ||
@@ -67,5 +64,5 @@ * Performs an HTTP GET request. | ||
```ts | ||
import { AbstractFetchService } from '@qrvey/fetch'; | ||
import { FetchService } from '@qrvey/fetch'; | ||
class MyFetchClient extends AbstractFetchService { | ||
class MyFetchClient extends FetchService { | ||
/** | ||
@@ -72,0 +69,0 @@ * Performs an HTTP GET request. |
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
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
43514
436
6
92
3