unfee 1.0.5 → 1.0.6
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/README.md +150 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1 +1,151 @@
|
|
|
1
1
|
# unfee
|
|
2
|
+
|
|
3
|
+
zero-dependencies TypeScript first tiny `fetch` wrapper that comes with good defaults.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
Install:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm install unfee
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Import:
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
import { unfee } from 'unfee'
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { unfee } from 'unfee'
|
|
23
|
+
|
|
24
|
+
const [error, data] = await unfee<{ id: string }>('https://jsonplaceholder.typicode.com/todos/1')
|
|
25
|
+
if (error) {
|
|
26
|
+
console.error(error)
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
console.log(data.id)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Benefits over plain `fetch`
|
|
33
|
+
|
|
34
|
+
- Simple API
|
|
35
|
+
- Treat non-2xx status codes as errors
|
|
36
|
+
- Retry failed requests
|
|
37
|
+
- Timeout support
|
|
38
|
+
- Instances with custom defaults
|
|
39
|
+
- Hooks
|
|
40
|
+
- TypeScript niceties
|
|
41
|
+
|
|
42
|
+
## JSON
|
|
43
|
+
|
|
44
|
+
JSON is used by default. `FormData`, `URLSearchParams`, or string bodies override the Content-Type automatically.
|
|
45
|
+
|
|
46
|
+
**Example:**
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
const [_, todos] = await unfee('/todos', {
|
|
50
|
+
method: 'GET',
|
|
51
|
+
data: { key: 'value' },
|
|
52
|
+
})
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Error handling
|
|
56
|
+
|
|
57
|
+
Error handling is a first-class citizen in `unfee`.
|
|
58
|
+
|
|
59
|
+
The function returns an error as its first value. When `response.ok` is `false`, the error will be populated accordingly.
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
const [error] = await ofetch('https://httpbin.org/status/404')
|
|
63
|
+
// ^
|
|
64
|
+
// fetch-error: Request failed: [GET https://httpbin.org/status/404]
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`unfee` comes with `HTTPError`, `ParseError` types.
|
|
68
|
+
|
|
69
|
+
## Timeout
|
|
70
|
+
|
|
71
|
+
You can specify a timeout (in milliseconds) to automatically abort a request.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
const [error, data] = await ofetch('/api', { timeout: 10000 })
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Retry
|
|
78
|
+
|
|
79
|
+
Requests are automatically retried when certain errors occur. By default, retries are triggered for the following status codes:
|
|
80
|
+
|
|
81
|
+
- `408` — Request Timeout
|
|
82
|
+
- `409` — Conflict
|
|
83
|
+
- `425` — Too Early
|
|
84
|
+
- `429` — Too Many Requests
|
|
85
|
+
- `500` — Internal Server Error
|
|
86
|
+
- `502` — Bad Gateway
|
|
87
|
+
- `503` — Service Unavailable
|
|
88
|
+
- `504` — Gateway Timeout
|
|
89
|
+
|
|
90
|
+
Requests using the `POST`, `PUT`, `PATCH`, and `DELETE` methods are **not retried by default** to avoid unintended side effects.
|
|
91
|
+
|
|
92
|
+
You can customize the retry behavior:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
const [error, data] = await unfee('/api', {
|
|
96
|
+
retry: {
|
|
97
|
+
times: 5,
|
|
98
|
+
delay: 500,
|
|
99
|
+
statusCode: new Set([500]),
|
|
100
|
+
},
|
|
101
|
+
})
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Global instances
|
|
105
|
+
|
|
106
|
+
You can create a new instance with a custom configuration to share common options across requests.
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { unfee } from 'unfee'
|
|
110
|
+
|
|
111
|
+
const api = unfee.extend({
|
|
112
|
+
baseUrl: 'http://api.test/',
|
|
113
|
+
headers: {
|
|
114
|
+
Authorization: 'Bearer xxx',
|
|
115
|
+
},
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
const [error, data] = await api('/endpoint', {
|
|
119
|
+
retry: {
|
|
120
|
+
times: 2,
|
|
121
|
+
},
|
|
122
|
+
})
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Hooks
|
|
126
|
+
|
|
127
|
+
You can hook into request lifecycle events using the `hooks` option. Each hook lets you run custom logic at a specific stage of the request.
|
|
128
|
+
|
|
129
|
+
Available hooks:
|
|
130
|
+
|
|
131
|
+
- `beforeRequest(options)` — called before the request is sent. Useful for modifying headers or request options.
|
|
132
|
+
- `afterResponse(request, response, options)` — called after a successful response is received.
|
|
133
|
+
- `onRequestError(error, request, options)` — triggered when a request fails before receiving a response.
|
|
134
|
+
- `onResponseError(error, response, request, options)` — triggered when the server responds with an error status.
|
|
135
|
+
- `onResponseParseError(error, response, request, options)` — called when response parsing fails.
|
|
136
|
+
- `onRequestRetry(retryCount, response, request, options)` — called before a request is retried.
|
|
137
|
+
|
|
138
|
+
Example:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
const [error, data] = await unfee('/api', {
|
|
142
|
+
hooks: {
|
|
143
|
+
beforeRequest(options) {
|
|
144
|
+
console.log('Sending request...')
|
|
145
|
+
},
|
|
146
|
+
afterResponse(request, response) {
|
|
147
|
+
console.log('Received response:', response.status)
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
})
|
|
151
|
+
```
|