Skip to content

Commit

Permalink
feat!: add interceptors. remove validator.
Browse files Browse the repository at this point in the history
  • Loading branch information
jd1378 committed Jul 28, 2022
1 parent 380f013 commit f88d479
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 117 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@

# Changelog

## v6.0.0

- remmove `validator`.
- add `interceptors`.

## v5.2.0

- fix a small issue when no header was given
Expand All @@ -17,6 +22,10 @@

- fix timeout functionality as the abort signal is now supported as of deno v1.11


Version v5.0.0+ is the recommended version now (abort controller is used now). please don't use v4 of fetch goody anymore.


## v4.0.0

- due to adding `timeout` option and the way it works, it may cause issues. so I release this as breaking change.
Expand Down
40 changes: 26 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,52 @@ This library offers a fetch wrapper that can:
- automatically add `Content-Type` header
- directly use objects for `body` as json (see below)
- send `form`, `formData`, `qs` (query string) easily from objects
- set a validator globally or per request, to reject when validator throws.
- accept a timeout option and abort when timeout is reached
- add `Accept` header with value `application/json, text/plain, */*` if not already set by you
- set global headers when creating the wrapper
- set a `baseURL` when creating the wrapper

Version v5.0.0+ is the recommended version now (abort controller is used now). please don't use v4 of fetch goody anymore.
- add `interceptors` when creating the wrapper or for individual requests

**Deno v1.11+ is required.**

## usage

you can import `wrapFetch` from `mod.ts` file.

```js
export { wrapFetch } from 'https://deno.land/x/fetch_goody@v5.2.0/mod.ts';
```ts
export { wrapFetch } from 'https://deno.land/x/fetch_goody@v6.0.0/mod.ts';
```

### wrapFetch

```js
```ts
// this simple
const wrappedfetch = wrapFetch();
```

Or

```js
```ts
// you can also pass your own wrapped fetch function, allowing for wrapping fetch multiple times
const wrappedfetch = wrapFetch({ fetch: yourFetch });
```

You can also add global interceptors:
```ts
const wrappedfetch = wrapFetch({
interceptors: {
request(init: ExtendedRequest) {
// add some header before each request is sent
// for example add some headers from your cookie-jar
},
}
});
```

#### using the new wrappedfetch

```js
// v3.0.0 : for sending a multipart/form-data body now you should use `formData`.
```ts
// for sending a multipart/form-data body now you should use `formData`.
const resp1 = await wrappedfetch("url",{
form: {
'foo': 'bar'
Expand Down Expand Up @@ -68,13 +78,15 @@ const resp3 = await wrappedfetch("url",{
}
}); // results to url being sent to be "url?foo=bar"

// adding a response validator where you can throw errors
// adding interceptors where you can throw errors and other stuff

const resp4 = await wrappedfetch("url",{
validator(response: Response, init: ExtendedRequest) {
if (response.status > 200) {
throw new Error('yada');
}
interceptors: {
response(init: ExtendedRequest, response: Response) {
if (response.status > 200) {
throw new Error('yada');
}
},
}
});

Expand Down
20 changes: 13 additions & 7 deletions extended_request_init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,23 @@ interface RequestInitDiff {
formData?: Record<string, string | string[]>;
/** if an object is passed, it will be sent as serialized json and header is set accordingly. */
body?: Record<string, unknown> | BodyInit | null;
/** a function that will be called before returning response.
* can be used for validating response and throwing errors */
validator?: Validator;
/** interceptors can be used for validating request and response and throwing errors */
interceptors?: Interceptors;
/** time in milliseconds which after the request should be cancelled and rejected */
timeout?: number;
}

export type Validator = (
response: Response,
init: ExtendedRequest,
) => void | Promise<void>;
export type Interceptors = {
/** function that is called just before a request is sent*/
request?: (
init: ExtendedRequest,
) => void | Promise<void>;
/** function that is called just before a response is returned from the fetch*/
response?: (
init: ExtendedRequest,
response: Response,
) => void | Promise<void>;
};

export type ExtendedRequestInit =
& RequestInitDiff
Expand Down
34 changes: 24 additions & 10 deletions fetch_wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as utils from "./utils.ts";
import {
ExtendedRequest,
ExtendedRequestInit,
Validator,
Interceptors,
} from "./extended_request_init.ts";

/**
Expand Down Expand Up @@ -69,25 +69,26 @@ export type WrapFetchOptions = {
fetch?: typeof fetch;
/** user agent header string */
userAgent?: string;
/** validator to run after each response with this fetch */
validator?: Validator;
/** if set, all requests will timeout after this amount of milliseconds passed */
timeout?: number;
/** if set, will be used as default headers. new added headers will be added on top of these. */
headers?: Headers;
/** if set, will be prepended to the target url using URL api. */
baseURL?: string | URL;
/** interceptors can be used for validating request and response and throwing errors */
interceptors?: Interceptors;
};

export function wrapFetch(options?: WrapFetchOptions) {
const {
fetch = globalThis.fetch,
userAgent,
validator,
interceptors,
timeout = 99999999,
headers,
baseURL,
} = options || {};

return async function wrappedFetch(
input: string | Request | URL,
init?: ExtendedRequestInit | RequestInit | undefined,
Expand Down Expand Up @@ -224,20 +225,33 @@ export function wrapFetch(options?: WrapFetchOptions) {
newInput = new URL(newInput, baseURL);
}

if (typeof interceptors?.request === "function") {
await interceptors.request(interceptedInit as ExtendedRequest);
}

if (
"interceptors" in interceptedInit &&
typeof interceptedInit.interceptors?.request === "function"
) {
await interceptedInit.interceptors.request(
interceptedInit as ExtendedRequest,
);
}

const response = await fetch(newInput, interceptedInit as RequestInit);
clearTimeout(timeoutId);

if (typeof validator === "function") {
await validator(response, interceptedInit as ExtendedRequest);
if (typeof interceptors?.response === "function") {
await interceptors.response(interceptedInit as ExtendedRequest, response);
}

if (
"validator" in interceptedInit &&
typeof interceptedInit.validator === "function"
"interceptors" in interceptedInit &&
typeof interceptedInit.interceptors?.response === "function"
) {
await interceptedInit.validator(
response,
await interceptedInit.interceptors.response(
interceptedInit as ExtendedRequest,
response,
);
}

Expand Down
Loading

0 comments on commit f88d479

Please sign in to comment.