Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/cap32/fetch-extra
🏹 Extra features for whatwg fetch and Request (Node.js and browser)
https://github.com/cap32/fetch-extra
ajax browser fetch node promise query request transformer xhr
Last synced: 25 days ago
JSON representation
🏹 Extra features for whatwg fetch and Request (Node.js and browser)
- Host: GitHub
- URL: https://github.com/cap32/fetch-extra
- Owner: Cap32
- Created: 2017-12-11T07:33:17.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2018-11-11T15:50:18.000Z (about 6 years ago)
- Last Synced: 2024-11-24T00:28:06.109Z (30 days ago)
- Topics: ajax, browser, fetch, node, promise, query, request, transformer, xhr
- Language: JavaScript
- Homepage:
- Size: 333 KB
- Stars: 3
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
Awesome Lists containing this project
README
# fetch-extra
[![Build Status](https://travis-ci.org/Cap32/fetch-extra.svg?branch=master)](https://travis-ci.org/Cap32/fetch-extra)
[![Coverage Status](https://coveralls.io/repos/github/Cap32/fetch-extra/badge.svg?branch=master)](https://coveralls.io/github/Cap32/fetch-extra?branch=master)
[![License](https://img.shields.io/badge/license-MIT_License-brightgreen.svg?style=flat)](https://github.com/Cap32/fetch-extra/blob/master/LICENSE)Extra features for [whatwg fetch](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch) and [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) like `query` object, JSON `body`, timeout, [abort](https://developers.google.com/web/updates/2017/09/abortable-fetch), `transformers`. Works for browser and Node.js.
## Table of Contents
- [Table of Contents](#table-of-contents)
- [Installations](#installations)
- [fetch](#fetch)
- [Request](#request)
- [New `Request#fetch(...options)` method](#new-requestfetchoptions-method)
- [Enhanced `url` option](#enhanced-url-option)
- [Enhanced `Request#clone(...options)` method](#enhanced-requestcloneoptions-method)
- [New `responseType` option](#new-responsetype-option)
- [New `query` option](#new-query-option)
- [Enhanced `body` option](#enhanced-body-option)
- [New `type` option](#new-type-option)
- [New `simple` option](#new-simple-option)
- [Polyfill `AbortController`](#polyfill-abortcontroller)
- [New `queryStringify` option](#new-querystringify-option)
- [New `queryParse` option](#new-queryparse-option)
- [New `queryTransformer` option](#new-querytransformer-option)
- [New `urlTransformer` option](#new-urltransformer-option)
- [New `headersTransformer` option](#new-headerstransformer-option)
- [New `bodyTransformer` option](#new-bodytransformer-option)
- [New `responseTransformer` option](#new-responsetransformer-option)
- [New `responseDataTransformer` option](#new-responsedatatransformer-option)
- [New `errorTransformer` option](#new-errortransformer-option)
- [Contributing](#contributing)
- [License](#license)## Installations
Using npm:
```bash
$ npm install fetch-extra
```Or using 1998 Script Tag:
```html
(Module exposed as `fetchExtra`)
```**To install fetch-extra with `window.fetch` polyfill, please istall `fetch-extra-polyfill` instead**
## fetch
```js
import fetch from "fetch-extra";
(async function main() {
const url = "https://swapi.co/api/people/";
const res = await fetch(url, {
method: "POST",
type: "json" /* json Content-Type header */,
responseType: "json" /* short for `await res.json()` */,
query: { token: "asdf" } /* query object */,
body: {
/* json body object */
firstName: "Luke",
familyName: "Skywalker"
}
});
console.log(res.name); /* Luke Skywalker */
})();
```##### Syntax
> Promise\ fetch(...options)
`...options` \<...String|Object|Request\>
- If `options` is a string, it is treated as a `URL`
- If `options` is a object, it is treated as `Request` options. Checkout below for detail. All [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) options are supportedLater `options` will similarly overwrite earlier ones.
##### Description
> The Fetch API provides an interface for fetching resources.
`fetch` syntax adapts to [WHATWG fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API):
```js
import fetch from "fetch-extra";
(async function main() {
const url = "https://swapi.co/api/people/1/";
const res = await fetch(url, { method: "GET" });
const luke = await res.json();
console.log(luke.name); /* Luke Skywalker */
})();
```But there are some extra options.
```js
const res = await fetch({
url: "https://swapi.co/api/people/1/",
query: { page: 32 },
responseType: "json",
timeout: 30000
});
```For more extra options and usages, please checkout below.
## Request
```js
import { Request } from "fetch-extra";
(async function main() {
const base = new Request({
url: "https://swapi.co/api/",
type: "json",
responseType: "json",
timeout: 30000,
async headersTransformer(headers) {
headers['access-token'] = await fakeGetToken(),
return headers;
},
});
const people = base.clone("/people");
const starships = base.clone("/starships");const luke = await people.fetch("/1");
const c3po = await people.fetch("/2");
const starDestroyer = await starships.fetch("/3");
})();
```##### Syntax
> \ new Request(...options)
`...options` \<...String|Object|Request\>
All options are the same with `fetch(...options)`.
##### Description
> The Request interface of the Fetch API represents a resource request.
Request syntax also adapts to [WHATWG Request](https://developer.mozilla.org/en-US/docs/Web/API/Request).
```js
import fetch, { Request } from "fetch-extra";
(async function main() {
const url = "https://swapi.co/api/people/1/";
const request = new Request(url);
const res = await fetch(request);
const luke = await res.json();
})();
```But there are some extra options and methods.
##### Why
`fetch()` is useful, but `new Request()` provides a way to inherit requests. It is recommended to create a base `Request` instance to share base url, `Content-Type` header, access token header, response type, error handler (by using [errorTransformer()](#new-errortransformer-option)), etc, and then `fetch()` or `clone()` the base request.
### New `Request#fetch(...options)` method
A shortcut for `fetch(request, ...options)`.
All options are the same with `fetch(...options)`.
```js
import { Request } from "fetch-extra";
const request = new Request(url);
const res = await request.fetch();
const luke = await res.json();
```Fetching with options:
```js
import { Request } from "fetch-extra";
const request = new Request(url);
const res = await request.fetch({ method: "DELETE" });
const luke = await res.json();
```The example above is equal to:
```js
import fetch, { Request } from "fetch-extra";
const request = new Request(url);
const res = await fetch(request, { method: "DELETE" });
const luke = await res.json();
```### Enhanced `url` option
`URLs` could be composed.
```js
const baseUrl = "https://swapi.co/api/";
const swRequest = new Request(baseUrl);const lukeRes = await swRequest.fetch("/people/1/");
/* final URL will be "https://swapi.co/api/people/1/" */const starShipRes = await swRequest.fetch("/starships/9/");
/* final URL will be "https://swapi.co/api/starships/9/" */
```To override earlier URL, just give a new URL starts with a protocol (like `http://` or `https://`):
```js
const swRequest = new Request("https://swapi.co/", options);
const pokeRes = swRequest.fetch("https://pokeapi.co/api/v2/");
/* final URL will be "https://pokeapi.co/api/v2/" */
```### Enhanced `Request#clone(...options)` method
```js
const baseRequest = new Request({
headers: { "Content-Type": "application/json" }
});const swRequest = baseRequest.clone("https://swapi.co/api/");
const luke = await swRequest.fetch("/people/1/");
const c3po = await swRequest.fetch("/people/2/");const pokeRequest = baseRequest.clone("https://pokeapi.co/api/v2/");
const bulbasaur = await pokeRequest.fetch("/pokemon/1/");
```The `...options` usages are the same with `fetch(...options)` and `new Request(...options)`
### New `responseType` option
Returning resolved data with specified type instead of `response` object.
```js
const options = { responseType: "json" };
const luke = await swRequest.fetch(
options
); /* <-- no need `await res.json()` */
console.log(luke.name); /* Luke Skywalker */
```In browser, `responseType` value could be one of `arrayBuffer`, `blob`, `formData`, `json` or `text`.
In Node.js, `formData` is NOT supported.
If `responseType` is `none`, it will return the original `response` object.
### New `query` option
```js
const results = await swRequest.fetch({ query: { search: "luke" } });
/* final URL will be "https://swapi.co/api/people?search=luke" */
````query` could be JSON object or string (like `name=luke&height=172`).
If `url` has search fields (like `https://swapi.co/api/people?search=luke`), query string will append to the search fields.
### Enhanced `body` option
```js
const results = await swRequest.fetch({
method: "POST",
body: { name: "Luke Skywalker" } /* <-- could be a JSON */
});
/* final body will be '{"name":"Luke Skywalker"}' */
```### New `type` option
```js
const results = await swRequest.fetch({
method: 'POST',
type: 'form'
body: { name: 'Luke Skywalker' },
});
/* final body will be 'name=Luke%20Skywalker' */
/* final header['Content-Type'] will be 'application/x-www-form-urlencoded' */
````type` value will auto set to headers `Content-Type`.
Value `form` is short for `application/x-www-form-urlencoded`, and `json` is short for `application/json`.
### New `simple` option
Will throw error if `response` status is non-2xx.
```js
await swRequest
.fetch({
simple: true,
url: "/400" /* simulate response with 400 HTTP status */
})
.catch(err => {
console.error(err); /* <-- Error: Bad Request */
});
```### Polyfill `AbortController`
Built-in [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) and [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) polyfill for [aborting fetch](https://developers.google.com/web/updates/2017/09/abortable-fetch).
```js
import fetch, { AbortController } from "fetch-extra";
(async function main() {
const abortController = new AbortController();
const fetchPromise = fetch("https://swapi.co/api/people/1", {
signal: abortController.signal
});
abortController.abort();
await fetchPromise.catch(err => {
if (err.name === "AbortError") console.warn("Aborted.");
else console.error(err.message);
});
})();
```### New `queryStringify` option
Setting a custom function in charge of serializing `query` object.
```js
import qs from "qs";const request = new Request({
queryStringify: qs.stringify
});
```By default, this function is [tiny-querystring](https://github.com/Cap32/tiny-querystring#stringifyobj) `stringify` function.
### New `queryParse` option
Setting a custom function in charge of parsing `query` string.
```js
import qs from "qs";const request = new Request({
queryParse: qs.parse
});
```By default, this function is [tiny-querystring](https://github.com/Cap32/tiny-querystring#stringifyobj) `parse` function.
### New `queryTransformer` option
Setting a function to transform `query` object, should return a new `query` object. Will be called before fetching.
```js
const baseRequest = new Request({
queryTransformer: (query) => { /* <-- queryTransformer */
query.accessToken = '',
return query;
},
});
const swRequest = baseRequest.clone('https://swapi.co/api/');
const results = await swRequest.fetch('/people', {
query: { search: 'luke' },
});
/* final URL will be "https://swapi.co/api/people?search=luke&accessToken=" */
```All transformers could return promises.
```js
const baseRequest = new Request({
async queryTransformer(query) { /* <-- async queryTransformer */
query.accessToken = await getTokenAsync(),
return query;
},
});
/* ... */
```### New `urlTransformer` option
Like `queryTransformer`, but transform `url`.
### New `headersTransformer` option
Like `queryTransformer`, but transform `headers`.
### New `bodyTransformer` option
Like `queryTransformer`, but transform `body`.
### New `responseTransformer` option
Transform [response](https://developer.mozilla.org/en-US/docs/Web/API/Response) instance.
```js
const baseRequest = new Request({
responseType: "json",
responseTransformer(response) {
/* <-- responseTransformer */
if (response.status === 404) {
throw new Error("Page not found");
}
return response;
}
});
/* ... */
```### New `responseDataTransformer` option
Like `responseTransformer`, but transform the data after `responseType` resolved.
```js
const baseRequest = new Request({
responseType: "json",
responseDataTransformer(json) {
/* <-- responseDataTransformer */
if (json) {
json.fullName = `${json.firstName} ${json.familyName}`;
}
return json;
}
});
/* ... */
```### New `errorTransformer` option
Transform error or rejection.
```js
const baseRequest = new Request({
errorTransformer(error) {
/* <-- errorTransformer */
if (error.name === "Abort") {
console.warn("Fetch aborted");
}
return error;
}
});
/* ... */
```## Contributing
Please [checkout CONTRIBUTING.md](/CONTRIBUTING.md)
## License
MIT