fch 3.0.0 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fetch.js +9 -15
- package/index.js +1 -0
- package/package.json +7 -5
- package/readme.md +185 -79
package/fetch.js
CHANGED
|
@@ -118,7 +118,7 @@ const create = (defaults = {}) => {
|
|
|
118
118
|
// Merge it, first the global and then the local
|
|
119
119
|
query = { ...fch.query, ...query };
|
|
120
120
|
// Absolute URL if possible; Default method; merge the default headers
|
|
121
|
-
request.url = createUrl(request.url
|
|
121
|
+
request.url = createUrl(request.url ?? fch.url, query, baseUrl);
|
|
122
122
|
request.method = (request.method ?? fch.method).toLowerCase();
|
|
123
123
|
request.headers = createHeaders(request.headers, fch.headers);
|
|
124
124
|
|
|
@@ -145,8 +145,8 @@ const create = (defaults = {}) => {
|
|
|
145
145
|
request = before(request);
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
// It should be cached
|
|
149
|
-
if (dedupe) {
|
|
148
|
+
// It should be cached and it's not being manually manipulated
|
|
149
|
+
if (dedupe && !request.signal) {
|
|
150
150
|
// It's already cached! Just return it
|
|
151
151
|
if (dedupe.get()) return dedupe.get();
|
|
152
152
|
|
|
@@ -161,6 +161,7 @@ const create = (defaults = {}) => {
|
|
|
161
161
|
};
|
|
162
162
|
|
|
163
163
|
// Default values
|
|
164
|
+
fch.url = defaults.url ?? "/";
|
|
164
165
|
fch.method = defaults.method ?? "get";
|
|
165
166
|
fch.query = defaults.query ?? {};
|
|
166
167
|
fch.headers = defaults.headers ?? {};
|
|
@@ -189,18 +190,11 @@ const create = (defaults = {}) => {
|
|
|
189
190
|
fch.put = put;
|
|
190
191
|
fch.del = del;
|
|
191
192
|
|
|
193
|
+
fch.create = create;
|
|
194
|
+
|
|
192
195
|
return fch;
|
|
193
196
|
};
|
|
194
197
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
// since the modules are deferred by default. Basically this is a big mess and
|
|
199
|
-
// I wish I could just do if `(typeof window !== 'undefined') window.fch = fch`,
|
|
200
|
-
// but unfortunately that's not possible now and I need this as a traditionally
|
|
201
|
-
// global definition, and then another file to import it as ESM. UGHHH
|
|
202
|
-
let glob = {};
|
|
203
|
-
if (typeof global !== "undefined") glob = global;
|
|
204
|
-
if (typeof window !== "undefined") glob = window;
|
|
205
|
-
glob.fch = create();
|
|
206
|
-
glob.fch.create = create;
|
|
198
|
+
const fch = create();
|
|
199
|
+
|
|
200
|
+
export default fch;
|
package/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const hasPlainBody=e=>{if(!e.headers["content-type"]&&["object","array"].includes(typeof e.body)&&!(e.body instanceof FormData))return!0},createUrl=(e,t,r)=>{let[o,a={}]=e.split("?");const s=new URLSearchParams({...Object.fromEntries(new URLSearchParams(t)),...Object.fromEntries(new URLSearchParams(a))}).toString();if(s&&(o=o+"?"+s),!r)return o;return new URL(o,r).href},createHeaders=(e,t)=>{const r={...t,...e};for(let e in r){const t=r[e];delete r[e],r[e.toLowerCase()]=t}return r},createDedupe=(e,t)=>({save:r=>(e.set(t,r),r),get:()=>e.get(t),clear:()=>e.delete(t)}),createFetch=(e,{after:t,dedupe:r,error:o,output:a})=>fetch(e.url,e).then((async e=>{r&&r.clear();let s={status:e.status,statusText:e.statusText,headers:{}};for(let t of e.headers.keys())s.headers[t.toLowerCase()]=e.headers.get(t);if(!e.ok){const t=new Error(e.statusText);return t.response=s,o(t)}const d=e.headers.get("content-type").includes("application/json");return s.body=await(d?e.json():e.text()),t&&(s=t(s)),"body"===a?s.body:s})),create=(e={})=>{const t=new Map,r=async(e,o={})=>{"object"!=typeof o&&(o={}),o="string"==typeof e?{url:e,...o}:e||{};let{dedupe:a=r.dedupe,output:s=r.output,baseURL:d=r.baseURL,baseUrl:n=d||r.baseUrl,query:u={},before:c=r.before,after:h=r.after,error:p=r.error,...l}=o;if(u={...r.query,...u},l.url=createUrl(l.url??r.url,u,n),l.method=(l.method??r.method).toLowerCase(),l.headers=createHeaders(l.headers,r.headers),"get"!==l.method&&(a=!1),a&&(a=createDedupe(t,l.url)),!["body","response"].includes(s)){throw new Error(`options.output needs to be either "body" (default) or "response", not "${s}"`)}return hasPlainBody(l)&&(l.body=JSON.stringify(l.body),l.headers["content-type"]="application/json; charset=utf-8"),c&&(l=c(l)),a&&!l.signal?a.get()?a.get():a.save(createFetch(l,{dedupe:a,output:s,error:p,after:h})):createFetch(l,{output:s,error:p,after:h})};r.url=e.url??"/",r.method=e.method??"get",r.query=e.query??{},r.headers=e.headers??{},r.dedupe=e.dedupe??!0,r.output=e.output??"body",r.credentials=e.credentials??"include",r.before=e.before??(e=>e),r.after=e.after??(e=>e),r.error=e.error??(e=>Promise.reject(e));return r.get=(e,t={})=>r(e,{...t}),r.head=(e,t={})=>r(e,{...t,method:"head"}),r.post=(e,t={})=>r(e,{...t,method:"post"}),r.patch=(e,t={})=>r(e,{...t,method:"patch"}),r.put=(e,t={})=>r(e,{...t,method:"put"}),r.del=(e,t={})=>r(e,{...t,method:"delete"}),r.create=create,r},fch=create();window.fch=fch;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fch",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"description": "Fetch interface with better promises, deduplication, defaults, etc.",
|
|
5
5
|
"homepage": "https://github.com/franciscop/fetch",
|
|
6
6
|
"repository": "https://github.com/franciscop/fetch.git",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"author": "Francisco Presencia <public@francisco.io> (https://francisco.io/)",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"scripts": {
|
|
12
|
+
"build": "terser --compress --mangle -- ./fetch.js | sed 's/export default fch;/window.fch=fch;/g' > ./index.js",
|
|
12
13
|
"start": "npm run watch # Start ~= Start dev",
|
|
13
14
|
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage --detectOpenHandles",
|
|
14
15
|
"watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch --coverage --detectOpenHandles"
|
|
@@ -21,19 +22,20 @@
|
|
|
21
22
|
"async",
|
|
22
23
|
"ajax"
|
|
23
24
|
],
|
|
24
|
-
"main": "./
|
|
25
|
-
"browser": "./
|
|
25
|
+
"main": "./fetch.js",
|
|
26
|
+
"browser": "./index.js",
|
|
26
27
|
"files": [
|
|
28
|
+
"index.js",
|
|
27
29
|
"fetch.js"
|
|
28
30
|
],
|
|
29
31
|
"type": "module",
|
|
30
32
|
"engines": {
|
|
31
33
|
"node": ">=18.0.0"
|
|
32
34
|
},
|
|
33
|
-
"dependencies": {},
|
|
34
35
|
"devDependencies": {
|
|
35
36
|
"jest": "^28.0.1",
|
|
36
|
-
"jest-fetch-mock": "^3.0.3"
|
|
37
|
+
"jest-fetch-mock": "^3.0.3",
|
|
38
|
+
"terser": "^5.13.1"
|
|
37
39
|
},
|
|
38
40
|
"jest": {
|
|
39
41
|
"testEnvironment": "jest-environment-node",
|
package/readme.md
CHANGED
|
@@ -1,47 +1,49 @@
|
|
|
1
|
-
# Fch [](https://www.npmjs.com/package/fch) [](https://www.npmjs.com/package/fch) [](https://github.com/franciscop/fetch/blob/master/index.js)
|
|
2
2
|
|
|
3
3
|
A tiny library to make API calls easier. Similar to Axios, but tiny size and simpler API:
|
|
4
4
|
|
|
5
5
|
```js
|
|
6
6
|
import api from "fch";
|
|
7
|
-
|
|
7
|
+
api.baseUrl = "https://pokeapi.co/";
|
|
8
|
+
const mew = await api.get("/pokemon/150");
|
|
8
9
|
console.log(mew);
|
|
9
10
|
```
|
|
10
11
|
|
|
11
|
-
-
|
|
12
|
-
- Automatically
|
|
13
|
-
-
|
|
14
|
-
- Await/Async Promises
|
|
15
|
-
-
|
|
16
|
-
- Easily define shared options straight on the root `fch.baseUrl = "https://...";`.
|
|
17
|
-
- Interceptors: `before` (the request), `after` (the response) and `error` (it fails).
|
|
12
|
+
- Create instances with shared options across requests.
|
|
13
|
+
- Automatically encode object and array bodies as JSON.
|
|
14
|
+
- Automatically decode JSON responses based on the headers.
|
|
15
|
+
- Await/Async Promises; `>= 400 and <= 100` will _reject_ with an error.
|
|
16
|
+
- Interceptors: `before` the request, `after` the response and catch with `error`.
|
|
18
17
|
- Deduplicates parallel GET requests.
|
|
19
|
-
-
|
|
18
|
+
- Works the same way in Node.js and the browser.
|
|
19
|
+
- No dependencies; include it with a simple `<script>` on the browser.
|
|
20
20
|
|
|
21
21
|
```js
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
import api from 'fch';
|
|
23
|
+
|
|
24
24
|
api.get(url, { headers, ...options })
|
|
25
25
|
api.head(url, { headers, ...options })
|
|
26
26
|
api.post(url, { body, headers, ...options })
|
|
27
27
|
api.patch(url, { body, headers, ...options })
|
|
28
28
|
api.put(url, { body, headers, ...options })
|
|
29
29
|
api.del(url, { body, headers, ...options })
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
30
|
+
|
|
31
|
+
api.create({ url, body, headers, ...options})
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
| Options | Default | Description |
|
|
35
|
+
| ----------------------| ----------| -----------------------------------|
|
|
36
|
+
| [`method`](#method) | `"get"` | Default method to use for the call |
|
|
37
|
+
| [`url`](#url) | `null` | The path or url for the request |
|
|
38
|
+
| [`baseUrl`](#url) | `null` | The shared base of the API |
|
|
39
|
+
| [`body`](#body) | `null` | The body to send with the request |
|
|
40
|
+
| [`query`](#query) | `{}` | Add query parameters to the URL |
|
|
41
|
+
| [`headers`](#headers) | `{}` | Shared headers across all requests |
|
|
42
|
+
| [`output`](#output) | `"body"` | The return value of the API call |
|
|
43
|
+
| [`dedupe`](#dedupe) | `true` | Reuse concurrently GET requests |
|
|
44
|
+
| [`before`](#interceptors) |`req => req` |Process the request before sending it |
|
|
45
|
+
| [`after`](#interceptors) |`res => res` |Process the response before returning it |
|
|
46
|
+
| [`error`](#interceptors) |`err => throw err` |Process errors before returning them |
|
|
45
47
|
|
|
46
48
|
## Getting Started
|
|
47
49
|
|
|
@@ -70,45 +72,78 @@ On the browser you can add it with a script and it will be available as `fch`:
|
|
|
70
72
|
|
|
71
73
|
## Options
|
|
72
74
|
|
|
75
|
+
These are all available options and their defaults:
|
|
76
|
+
|
|
73
77
|
```js
|
|
74
78
|
import api from 'fch';
|
|
75
79
|
|
|
76
|
-
// General options with their defaults;
|
|
77
|
-
api.baseUrl = null; // Set an API endpoint
|
|
80
|
+
// General options with their defaults; all of these are also parameters:
|
|
78
81
|
api.method = 'get'; // Default method to use for api()
|
|
79
|
-
api.
|
|
82
|
+
api.url = '/'; // Relative or absolute url where the request is sent
|
|
83
|
+
api.baseUrl = null; // Set an API base URL reused all across requests
|
|
84
|
+
api.query = {}; // Merged with the query parameters passed manually
|
|
85
|
+
api.headers = {}; // Merged with the headers on a per-request basis
|
|
80
86
|
|
|
81
87
|
// Control simple variables
|
|
82
|
-
api.dedupe = true; // Avoid parallel GET requests to the same path
|
|
83
88
|
api.output = 'body'; // Return the body; use 'response' for the full response
|
|
89
|
+
api.dedupe = true; // Avoid sending concurrent GET requests to the same path
|
|
84
90
|
|
|
85
91
|
// Interceptors
|
|
86
92
|
api.before = req => req;
|
|
87
93
|
api.after = res => res;
|
|
88
94
|
api.error = err => Promise.reject(err);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
They can all be defined globally as shown above, passed manually as the options argument, or be used when [creating a new instance](#create-an-instance).
|
|
98
|
+
|
|
99
|
+
### Method
|
|
100
|
+
|
|
101
|
+
The HTTP method to make the request. When using the shorthand, it defaults to `GET`. We recommend using the method syntax:
|
|
89
102
|
|
|
90
|
-
|
|
91
|
-
api
|
|
103
|
+
```js
|
|
104
|
+
import api from 'fch';
|
|
105
|
+
|
|
106
|
+
api.get('/cats');
|
|
107
|
+
api.post('/cats', { body: { name: 'snowball' } });
|
|
108
|
+
api.put(`/cats/3`, { body: { name: 'snowball' }});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
You can use it with the plain function as an option parameter. The methods are all lowercase but the option as a parameter is case insensitive; it can be either uppercase or lowercase:
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
// Recommended way of dealing with methods:
|
|
115
|
+
api.get(...);
|
|
116
|
+
|
|
117
|
+
// INVALID; won't work
|
|
118
|
+
api.GET(...);
|
|
119
|
+
|
|
120
|
+
// Both of these are valid:
|
|
121
|
+
api({ method; 'GET' })
|
|
122
|
+
api({ method; 'get'})
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Example: adding a new cat and fixing a typo:
|
|
126
|
+
|
|
127
|
+
```js
|
|
128
|
+
import api from 'fch';
|
|
92
129
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
api.post(
|
|
96
|
-
api.put(
|
|
97
|
-
// ...
|
|
130
|
+
const cats = await api.get('/cats');
|
|
131
|
+
console.log(cats);
|
|
132
|
+
const { id } = await api.post('/cats', { body: { name: 'snowbll' } });
|
|
133
|
+
await api.put(`/cats/${id}`, { body: { name: 'snowball' }})
|
|
98
134
|
```
|
|
99
135
|
|
|
100
|
-
###
|
|
136
|
+
### Url
|
|
101
137
|
|
|
102
|
-
|
|
138
|
+
Specify where to send the request to. It's normally the first argument, though technically you can use both styles:
|
|
103
139
|
|
|
104
140
|
```js
|
|
105
|
-
// All of these methods are valid
|
|
106
141
|
import api from 'fch';
|
|
107
142
|
|
|
108
|
-
//
|
|
143
|
+
// Recommended way of specifying the Url
|
|
109
144
|
await api.post('/hello', { body: '...', headers: {} })
|
|
110
145
|
|
|
111
|
-
//
|
|
146
|
+
// These are also valid if you prefer their style; we won't judge
|
|
112
147
|
await api('/hello', { method: 'post', body: '...', headers: {} });
|
|
113
148
|
await api({ url: '/hello', method: 'post', headers: {}, body: '...' });
|
|
114
149
|
await api.post({ url: '/hello', headers: {}, body: '...' });
|
|
@@ -123,9 +158,11 @@ api.get('/hello');
|
|
|
123
158
|
// Called https//api.filemon.io/hello
|
|
124
159
|
```
|
|
125
160
|
|
|
161
|
+
> Note: with Node.js you need to either set an absolute baseUrl or make the URL absolute
|
|
162
|
+
|
|
126
163
|
### Body
|
|
127
164
|
|
|
128
|
-
The `body` can be a string, a plain object|array or a FormData instance. If it's an object, it'll be stringified and the header `application/json` will be added. Otherwise it'll be sent as plain text:
|
|
165
|
+
The `body` can be a string, a plain object|array or a FormData instance. If it's an array or object, it'll be stringified and the header `application/json` will be added. Otherwise it'll be sent as plain text:
|
|
129
166
|
|
|
130
167
|
```js
|
|
131
168
|
import api from 'api';
|
|
@@ -142,6 +179,46 @@ form.onsubmit = e => {
|
|
|
142
179
|
};
|
|
143
180
|
```
|
|
144
181
|
|
|
182
|
+
The methods `GET` and `HEAD` do not accept a body and it'll be ignored.
|
|
183
|
+
|
|
184
|
+
The **response body** will be returned by default as the output of the call:
|
|
185
|
+
|
|
186
|
+
```js
|
|
187
|
+
const body = await api.get('/cats');
|
|
188
|
+
console.log(body);
|
|
189
|
+
// [{ id: 1, }, ...]
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
When the server specifies the header `Content-Type` as `application/json`, then we'll attempt to parse the response body and return that as the variable. Otherwise, the plain text will be returned.
|
|
193
|
+
|
|
194
|
+
When the function returns the response (if you set `output: "response"` as an option), then the body can be accessed as `response.body`:
|
|
195
|
+
|
|
196
|
+
```js
|
|
197
|
+
const response = await api.get('/cats', { output: 'response' });
|
|
198
|
+
console.log(response.body);
|
|
199
|
+
// [{ id: 1, }, ...]
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
### Query
|
|
204
|
+
|
|
205
|
+
You can easily pass GET query parameters by using the option `query`:
|
|
206
|
+
|
|
207
|
+
```js
|
|
208
|
+
api.get('/cats', { query: { limit: 3 } });
|
|
209
|
+
// /cats?limit=3
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
While rare, some times you might want to persist a query parameter across requests and always include it; in that case, you can define it globally and it'll be added to every request:
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
import api from 'fch';
|
|
216
|
+
api.query.myparam = 'abc';
|
|
217
|
+
|
|
218
|
+
api.get('/cats', { query: { limit: 3 } });
|
|
219
|
+
// /cats?limit=3&myparam=abc
|
|
220
|
+
```
|
|
221
|
+
|
|
145
222
|
|
|
146
223
|
### Headers
|
|
147
224
|
|
|
@@ -150,13 +227,28 @@ You can define headers globally, in which case they'll be added to every request
|
|
|
150
227
|
|
|
151
228
|
```js
|
|
152
229
|
import api from 'fch';
|
|
153
|
-
api.headers.abc = 'def';
|
|
154
230
|
|
|
155
|
-
|
|
231
|
+
// Globally, so they are reused across all requests
|
|
232
|
+
api.headers.a = 'b';
|
|
233
|
+
|
|
234
|
+
// With an interceptor, in case you need dynamic headers per-request
|
|
235
|
+
api.before = req => {
|
|
236
|
+
req.headers.c = 'd';
|
|
237
|
+
return req;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// Set them for this single request:
|
|
241
|
+
api.get('/hello', { headers: { e: 'f' } });
|
|
156
242
|
// Total headers on the request:
|
|
157
|
-
// {
|
|
243
|
+
// { a: 'b', c: 'd', e: 'f' }
|
|
158
244
|
```
|
|
159
245
|
|
|
246
|
+
When to use each?
|
|
247
|
+
|
|
248
|
+
- If you need headers shared across all requests, like an API key, then the global one is the best place.
|
|
249
|
+
- When you need to extract them dynamically from somewhere it's better to use the .before() interceptor. An example would be the user Authorization token.
|
|
250
|
+
- When it changes on each request, it's not consistent or it's an one-off, use the option argument.
|
|
251
|
+
|
|
160
252
|
|
|
161
253
|
### Output
|
|
162
254
|
|
|
@@ -203,7 +295,7 @@ fch('/a', { dedupe: true }); // [DEFAULT] Dedupes GET requests
|
|
|
203
295
|
fch('/a', { dedupe: false }) // All fetch() calls trigger a network call
|
|
204
296
|
```
|
|
205
297
|
|
|
206
|
-
> We do not support deduping other methods
|
|
298
|
+
> We do not support deduping other methods besides `GET` right now
|
|
207
299
|
|
|
208
300
|
Note that opting out of deduping a request will _also_ make that request not be reusable, see this test for details:
|
|
209
301
|
|
|
@@ -255,32 +347,6 @@ fch.error = async err => {
|
|
|
255
347
|
```
|
|
256
348
|
|
|
257
349
|
|
|
258
|
-
### Define shared options
|
|
259
|
-
|
|
260
|
-
You can also define values straight away:
|
|
261
|
-
|
|
262
|
-
```js
|
|
263
|
-
import api from "fch";
|
|
264
|
-
|
|
265
|
-
api.baseUrl = "https://pokeapi.co/";
|
|
266
|
-
|
|
267
|
-
const mew = await api.get("/pokemon/150");
|
|
268
|
-
console.log(mew);
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
If you prefer Axios' style of outputting the whole response, you can do:
|
|
272
|
-
|
|
273
|
-
```js
|
|
274
|
-
// Default, already only returns the data on a successful call
|
|
275
|
-
api.output = "data";
|
|
276
|
-
const name = await api.get("/users/1").name;
|
|
277
|
-
|
|
278
|
-
// Axios-like
|
|
279
|
-
api.output = "response";
|
|
280
|
-
const name = await api.get("/users/1").data.name;
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
|
|
284
350
|
## How to
|
|
285
351
|
|
|
286
352
|
### Stop errors from throwing
|
|
@@ -332,7 +398,7 @@ const body = await fch.get('/blabla');
|
|
|
332
398
|
```
|
|
333
399
|
|
|
334
400
|
|
|
335
|
-
### Set
|
|
401
|
+
### Set authorization headers
|
|
336
402
|
|
|
337
403
|
You can set that globally as a header:
|
|
338
404
|
|
|
@@ -387,14 +453,54 @@ fch.get('/hello'); // Gets http://localhost:3000/hello (or wherever you are)
|
|
|
387
453
|
|
|
388
454
|
Note: for server-side (Node.js) usage, you always want to set `baseUrl`.
|
|
389
455
|
|
|
390
|
-
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
### Cancel ongoing requests
|
|
459
|
+
|
|
460
|
+
You can cancel ongoing requests [similarly to native fetch()](https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort#examples), by passing it a signal:
|
|
461
|
+
|
|
462
|
+
```js
|
|
463
|
+
import api from 'fch';
|
|
464
|
+
|
|
465
|
+
const controller = new AbortController();
|
|
466
|
+
const signal = controller.signal;
|
|
467
|
+
|
|
468
|
+
abortButton.addEventListener('click', () => {
|
|
469
|
+
controller.abort();
|
|
470
|
+
console.log('Download aborted');
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
api.get(url, { signal });
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
### Define shared options
|
|
479
|
+
|
|
480
|
+
You can also define values straight away:
|
|
481
|
+
|
|
482
|
+
```js
|
|
483
|
+
import api from "fch";
|
|
484
|
+
|
|
485
|
+
api.baseUrl = "https://pokeapi.co/";
|
|
486
|
+
|
|
487
|
+
const mew = await api.get("/pokemon/150");
|
|
488
|
+
console.log(mew);
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
You can also [create an instance](#create-an-instance) that will have the same options for all requests made with that instance.
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
### Node.js vs Browser
|
|
391
496
|
|
|
392
497
|
First, we use the native Node.js' fetch() and the browser's native fetch(), so any difference between those also applies to this library. For example, if you were to call `"/"` in the browser it'd refer to the current URL, while in Node.js it'd fail since you need to specify the full URL. Some other places where you might find differences: CORS, cache, etc.
|
|
393
498
|
|
|
394
499
|
In the library itself there's nothing different between the browser and Node.js, but it might be interesting to note that (if/when implemented) things like cache, etc. in Node.js are normally long-lived and shared, while in a browser request it'd bound to the request itself.
|
|
395
500
|
|
|
396
501
|
|
|
397
|
-
|
|
502
|
+
|
|
503
|
+
### Differences with Axios
|
|
398
504
|
|
|
399
505
|
The main difference is that things are simplified with fch:
|
|
400
506
|
|
|
@@ -412,9 +518,9 @@ axios.interceptors.request.use(fn);
|
|
|
412
518
|
fch.before = fn;
|
|
413
519
|
```
|
|
414
520
|
|
|
415
|
-
API size is also strikingly different, with **7.8kb** for Axios and **1.
|
|
521
|
+
API size is also strikingly different, with **7.8kb** for Axios and **1.1kb** for fch.
|
|
416
522
|
|
|
417
523
|
As disadvantages, I can think of two major ones for `fch`:
|
|
418
524
|
|
|
419
525
|
- Requires Node.js 18+, which is the version that includes `fetch()` by default.
|
|
420
|
-
- Does not support
|
|
526
|
+
- Does not support many of the more advanced options, like `onUploadProgress` nor `onDownloadProgress`.
|