fch 3.0.0 → 3.0.1
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 +2 -2
- package/package.json +1 -1
- package/readme.md +144 -31
package/fetch.js
CHANGED
|
@@ -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
|
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -4,7 +4,7 @@ A tiny library to make API calls easier. Similar to Axios, but tiny size and sim
|
|
|
4
4
|
|
|
5
5
|
```js
|
|
6
6
|
import api from "fch";
|
|
7
|
-
const mew = await api("https://pokeapi.co/pokemon/150");
|
|
7
|
+
const mew = await api.get("https://pokeapi.co/pokemon/150");
|
|
8
8
|
console.log(mew);
|
|
9
9
|
```
|
|
10
10
|
|
|
@@ -19,29 +19,30 @@ console.log(mew);
|
|
|
19
19
|
- Configurable to return either just the body, or the full response.
|
|
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
|
+
| `url` | `null` | The path or full url for the request |
|
|
37
|
+
| `baseUrl` | `null` | The shared base of the API |
|
|
38
|
+
| `method` | `"get"` | Default method to use for the call |
|
|
39
|
+
| `query` | `{}` | Add query parameters to the URL |
|
|
40
|
+
| `headers` | `{}` | Shared headers across all requests |
|
|
41
|
+
| `dedupe` | `true` | Reuse GET requests made concurrently |
|
|
42
|
+
| `output` | `"body"` | The return value of the API call |
|
|
43
|
+
| `before` | `req => req` | Process the request before sending it |
|
|
44
|
+
| `after` | `res => res` | Process the response before returning it |
|
|
45
|
+
| `error` | `err => throw err` | Process errors before returning them |
|
|
45
46
|
|
|
46
47
|
## Getting Started
|
|
47
48
|
|
|
@@ -73,9 +74,10 @@ On the browser you can add it with a script and it will be available as `fch`:
|
|
|
73
74
|
```js
|
|
74
75
|
import api from 'fch';
|
|
75
76
|
|
|
76
|
-
// General options with their defaults;
|
|
77
|
-
api.baseUrl = null; // Set an API
|
|
77
|
+
// General options with their defaults; all of these are also parameters:
|
|
78
|
+
api.baseUrl = null; // Set an API base URL reused all across requests
|
|
78
79
|
api.method = 'get'; // Default method to use for api()
|
|
80
|
+
api.query = {}; // Is merged with the query parameters passed manually
|
|
79
81
|
api.headers = {}; // Is merged with the headers on a per-request basis
|
|
80
82
|
|
|
81
83
|
// Control simple variables
|
|
@@ -97,18 +99,54 @@ api.put(url, { body, headers, ... });
|
|
|
97
99
|
// ...
|
|
98
100
|
```
|
|
99
101
|
|
|
100
|
-
###
|
|
102
|
+
### Method
|
|
103
|
+
|
|
104
|
+
The HTTP method to make the request. When using the shorthand, it defaults to `GET`. We recommend using the method syntax:
|
|
105
|
+
|
|
106
|
+
```js
|
|
107
|
+
import api from 'fch';
|
|
108
|
+
|
|
109
|
+
api.get('/cats');
|
|
110
|
+
api.post('/cats', { body: { name: 'snowball' } });
|
|
111
|
+
api.put(`/cats/3`, { body: { name: 'snowball' }});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
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:
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
// Recommended way of dealing with methods:
|
|
118
|
+
api.get(...);
|
|
119
|
+
|
|
120
|
+
// INVALID; won't work
|
|
121
|
+
api.GET(...);
|
|
122
|
+
|
|
123
|
+
// Both of these are valid:
|
|
124
|
+
api({ method; 'GET' })
|
|
125
|
+
api({ method; 'get'})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Example: adding a new cat and fixing a typo:
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
import api from 'fch';
|
|
132
|
+
|
|
133
|
+
const cats = await api.get('/cats');
|
|
134
|
+
console.log(cats);
|
|
135
|
+
const { id } = await api.post('/cats', { body: { name: 'snowbll' } });
|
|
136
|
+
await api.put(`/cats/${id}`, { body: { name: 'snowball' }})
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Url
|
|
101
140
|
|
|
102
|
-
|
|
141
|
+
Specify where to send the request to. It's normally the first argument, though technically you can use both styles:
|
|
103
142
|
|
|
104
143
|
```js
|
|
105
|
-
// All of these methods are valid
|
|
106
144
|
import api from 'fch';
|
|
107
145
|
|
|
108
|
-
//
|
|
146
|
+
// Recommended way of specifying the Url
|
|
109
147
|
await api.post('/hello', { body: '...', headers: {} })
|
|
110
148
|
|
|
111
|
-
//
|
|
149
|
+
// These are also valid if you prefer their style; we won't judge
|
|
112
150
|
await api('/hello', { method: 'post', body: '...', headers: {} });
|
|
113
151
|
await api({ url: '/hello', method: 'post', headers: {}, body: '...' });
|
|
114
152
|
await api.post({ url: '/hello', headers: {}, body: '...' });
|
|
@@ -123,9 +161,11 @@ api.get('/hello');
|
|
|
123
161
|
// Called https//api.filemon.io/hello
|
|
124
162
|
```
|
|
125
163
|
|
|
164
|
+
> Note: with Node.js you need to either set an absolute baseUrl or make the URL absolute
|
|
165
|
+
|
|
126
166
|
### Body
|
|
127
167
|
|
|
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:
|
|
168
|
+
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
169
|
|
|
130
170
|
```js
|
|
131
171
|
import api from 'api';
|
|
@@ -142,6 +182,46 @@ form.onsubmit = e => {
|
|
|
142
182
|
};
|
|
143
183
|
```
|
|
144
184
|
|
|
185
|
+
The methods `GET` and `HEAD` do not accept a body and it'll be ignored.
|
|
186
|
+
|
|
187
|
+
The **response body** will be returned by default as the output of the call:
|
|
188
|
+
|
|
189
|
+
```js
|
|
190
|
+
const body = await api.get('/cats');
|
|
191
|
+
console.log(body);
|
|
192
|
+
// [{ id: 1, }, ...]
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
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.
|
|
196
|
+
|
|
197
|
+
When the function returns the response (if you set `output: "response"` as an option), then the body can be accessed as `response.body`:
|
|
198
|
+
|
|
199
|
+
```js
|
|
200
|
+
const response = await api.get('/cats', { output: 'response' });
|
|
201
|
+
console.log(response.body);
|
|
202
|
+
// [{ id: 1, }, ...]
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
### Query
|
|
207
|
+
|
|
208
|
+
You can easily pass GET query parameters by using the option `query`:
|
|
209
|
+
|
|
210
|
+
```js
|
|
211
|
+
api.get('/cats', { query: { limit: 3 } });
|
|
212
|
+
// /cats?limit=3
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
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:
|
|
216
|
+
|
|
217
|
+
```js
|
|
218
|
+
import api from 'fch';
|
|
219
|
+
api.query.myparam = 'abc';
|
|
220
|
+
|
|
221
|
+
api.get('/cats', { query: { limit: 3 } });
|
|
222
|
+
// /cats?limit=3&myparam=abc
|
|
223
|
+
```
|
|
224
|
+
|
|
145
225
|
|
|
146
226
|
### Headers
|
|
147
227
|
|
|
@@ -150,13 +230,28 @@ You can define headers globally, in which case they'll be added to every request
|
|
|
150
230
|
|
|
151
231
|
```js
|
|
152
232
|
import api from 'fch';
|
|
153
|
-
api.headers.abc = 'def';
|
|
154
233
|
|
|
155
|
-
|
|
234
|
+
// Globally, so they are reused across all requests
|
|
235
|
+
api.headers.a = 'b';
|
|
236
|
+
|
|
237
|
+
// With an interceptor, in case you need dynamic headers per-request
|
|
238
|
+
api.before = req => {
|
|
239
|
+
req.headers.c = 'd';
|
|
240
|
+
return req;
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// Set them for this single request:
|
|
244
|
+
api.get('/hello', { headers: { e: 'f' } });
|
|
156
245
|
// Total headers on the request:
|
|
157
|
-
// {
|
|
246
|
+
// { a: 'b', c: 'd', e: 'f' }
|
|
158
247
|
```
|
|
159
248
|
|
|
249
|
+
When to use each?
|
|
250
|
+
|
|
251
|
+
- If you need headers shared across all requests, like an API key, then the global one is the best place.
|
|
252
|
+
- 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.
|
|
253
|
+
- When it changes on each request, it's not consistent or it's an one-off, use the option argument.
|
|
254
|
+
|
|
160
255
|
|
|
161
256
|
### Output
|
|
162
257
|
|
|
@@ -203,7 +298,7 @@ fch('/a', { dedupe: true }); // [DEFAULT] Dedupes GET requests
|
|
|
203
298
|
fch('/a', { dedupe: false }) // All fetch() calls trigger a network call
|
|
204
299
|
```
|
|
205
300
|
|
|
206
|
-
> We do not support deduping other methods
|
|
301
|
+
> We do not support deduping other methods besides `GET` right now
|
|
207
302
|
|
|
208
303
|
Note that opting out of deduping a request will _also_ make that request not be reusable, see this test for details:
|
|
209
304
|
|
|
@@ -387,6 +482,24 @@ fch.get('/hello'); // Gets http://localhost:3000/hello (or wherever you are)
|
|
|
387
482
|
|
|
388
483
|
Note: for server-side (Node.js) usage, you always want to set `baseUrl`.
|
|
389
484
|
|
|
485
|
+
### How to cancel an ongoing request?
|
|
486
|
+
|
|
487
|
+
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:
|
|
488
|
+
|
|
489
|
+
```js
|
|
490
|
+
import api from 'fch';
|
|
491
|
+
|
|
492
|
+
const controller = new AbortController();
|
|
493
|
+
const signal = controller.signal;
|
|
494
|
+
|
|
495
|
+
abortButton.addEventListener('click', () => {
|
|
496
|
+
controller.abort();
|
|
497
|
+
console.log('Download aborted');
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
api.get(url, { signal });
|
|
501
|
+
```
|
|
502
|
+
|
|
390
503
|
### What are the differences in Node.js vs Browser?
|
|
391
504
|
|
|
392
505
|
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.
|
|
@@ -417,4 +530,4 @@ API size is also strikingly different, with **7.8kb** for Axios and **1.9kb** fo
|
|
|
417
530
|
As disadvantages, I can think of two major ones for `fch`:
|
|
418
531
|
|
|
419
532
|
- Requires Node.js 18+, which is the version that includes `fetch()` by default.
|
|
420
|
-
- Does not support
|
|
533
|
+
- Does not support many of the more advanced options, like `onUploadProgress` nor `onDownloadProgress`.
|