Skip to content

Commit

Permalink
fix(callapi,callapi-legacy): enhance error handling and improve reque…
Browse files Browse the repository at this point in the history
…st deduplication

- Update the resolveHeaders function to handle various types of auth and body options
- Add requestKey option to callApi function in dev/src/client.ts
- Enhance error handling in createFetchClient to better distinguish between HTTP and JavaScript errors
- Improve request deduplication logic to provide more informative abort messages
- Add Register interface to allow custom meta types
  • Loading branch information
Ryan-Zayne committed Nov 15, 2024
1 parent 1f0fb3b commit 81ac2d0
Show file tree
Hide file tree
Showing 19 changed files with 380 additions and 209 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/autofix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9.12.3
version: 9.13.1

- name: Setup Node.js
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/changeset--release-and-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9.12.3
version: 9.13.1

- name: Setup Node.js 20.x
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lint-and-type.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9.12.3
version: 9.13.1

- name: Setup Node.js
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/size-limit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9.12.3
version: 9.13.1

- name: Setup Node.js
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test--release-and-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9.12.3
version: 9.13.1

- name: Setup Node.js 20.x
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
Expand Down
3 changes: 1 addition & 2 deletions dev/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ import { createFetchClient } from "@zayne-labs/callapi";
// import { createFetchClient } from "./src";

const callApi = createFetchClient({
dedupeStrategy: "defer",
dedupeStrategy: "cancel",
});

const [foo1, foo2, foo3, foo4] = await Promise.all([
callApi("https://dummyjson.com/products/:id", {
method: "GET",
params: [1],
requestKey: "hello",
}),

callApi("https://dummyjson.com/products/:id", {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@zayne-labs/callapi-root",
"type": "module",
"version": "0.0.0",
"packageManager": "pnpm@9.12.3",
"packageManager": "pnpm@9.13.1",
"scripts": {
"build": "pnpm --filter \"./packages/*\" build",
"build:dev": "pnpm --filter \"./packages/*\" build:dev",
Expand Down
2 changes: 1 addition & 1 deletion packages/callapi-legacy/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zayne-labs/callapi-legacy",
"type": "module",
"version": "1.0.0-rc.7",
"version": "1.0.0-rc.10",
"description": "A lightweight wrapper over fetch with quality of life improvements like built-in request cancellation, retries, interceptors and more",
"author": "Ryan Zayne",
"license": "MIT",
Expand Down
38 changes: 25 additions & 13 deletions packages/callapi-legacy/src/createFetchClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import type {
CallApiExtraOptions,
GetCallApiResult,
InterceptorUnion,
PossibleHTTPError,
PossibleJavaScriptError,
RequestOptions,
ResultModeUnion,
} from "./types";
Expand All @@ -25,7 +27,7 @@ import {
waitUntil,
} from "./utils/common";
import { createCombinedSignal, createTimeoutSignal } from "./utils/polyfills";
import { isFunction, isObject } from "./utils/typeof";
import { isFunction, isPlainObject } from "./utils/typeof";

export const createFetchClient = <
TBaseData,
Expand Down Expand Up @@ -152,7 +154,7 @@ export const createFetchClient = <
const defaultRequestOptions = {
method: "GET",
// eslint-disable-next-line perfectionist/sort-objects
body: isObject(body) ? options.bodySerializer(body) : body,
body: isPlainObject(body) ? options.bodySerializer(body) : body,

headers: resolveHeaders({ auth: options.auth, baseHeaders, body, headers }),

Expand Down Expand Up @@ -180,10 +182,11 @@ export const createFetchClient = <
const prevRequestInfo = requestInfoCacheOrNull?.get(requestKey);

if (prevRequestInfo && options.dedupeStrategy === "cancel") {
const reason = new DOMException(
`Request aborted as another request to the endpoint: ${url}, with the same request options was initiated.`,
"AbortError"
);
const message = requestKey
? `Request aborted as another request with the same request key: '${requestKey}' was initiated while the current request was in progress.`
: `Request aborted as another request to the endpoint: '${url}', with the same request options was initiated while the current request was in progress.`;

const reason = new DOMException(message, "AbortError");

prevRequestInfo.controller.abort(reason);
}
Expand Down Expand Up @@ -282,7 +285,7 @@ export const createFetchClient = <

options.onResponse?.({
data: validSuccessData,
errorData: null,
error: null,
options,
request,
response: options.shouldCloneResponse ? response.clone() : response,
Expand Down Expand Up @@ -340,27 +343,30 @@ export const createFetchClient = <
}

if (isHTTPErrorInstance<TErrorData>(error)) {
const { errorData, response } = error;
const { response } = error;

const possibleHttpError = (generalErrorResult as { error: PossibleHTTPError<TErrorData> })
.error;

await executeInterceptors(
options.onResponseError?.({
errorData,
error: possibleHttpError,
options,
request,
response: options.shouldCloneResponse ? response.clone() : response,
}),

options.onResponse?.({
data: null,
errorData,
error: possibleHttpError,
options,
request,
response: options.shouldCloneResponse ? response.clone() : response,
}),

// == Also call the onError interceptor
options.onError?.({
error,
error: possibleHttpError,
options,
request,
response: options.shouldCloneResponse ? response.clone() : response,
Expand All @@ -372,13 +378,19 @@ export const createFetchClient = <
return generalErrorResult;
}

const possibleJavascriptError = (generalErrorResult as { error: PossibleJavaScriptError }).error;

await executeInterceptors(
// == At this point only the request errors exist, so the request error interceptor is called
options.onRequestError?.({ error: error as Error, options, request }),
options.onRequestError?.({
error: possibleJavascriptError,
options,
request,
}),

// == Also call the onError interceptor
options.onError?.({
error: (generalErrorResult as { error: never }).error,
error: possibleJavascriptError,
options,
request,
response: null,
Expand Down
6 changes: 3 additions & 3 deletions packages/callapi-legacy/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ export { callApi, createFetchClient } from "./createFetchClient";

export type {
CallApiConfig,
CallApiErrorVariant,
CallApiResultErrorVariant,
CallApiExtraOptions,
CallApiSuccessVariant,
CallApiResultSuccessVariant,
ErrorContext,
RequestContext,
RequestErrorContext,
RequestOptions,
ResponseContext,
ResponseErrorContext,
SuccessResponseContext,
SuccessContext,
} from "./types";

export * from "./utils";
Loading

0 comments on commit 81ac2d0

Please sign in to comment.