create-request 0.0.1-beta.2 → 0.0.1-beta.4
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 +188 -451
- package/dist/library/BaseRequest.d.ts +29 -3
- package/dist/library/BodyRequest.d.ts +14 -1
- package/dist/library/ResponseWrapper.d.ts +22 -11
- package/dist/library/enums.d.ts +24 -8
- package/dist/library/index.d.ts +5 -2
- package/dist/library/index.esm.js +390 -79
- package/dist/library/index.js +390 -78
- package/dist/library/types.d.ts +14 -3
- package/dist/library/utils/Config.d.ts +69 -0
- package/dist/library/utils/CookieUtils.d.ts +9 -0
- package/dist/library/utils/CsrfUtils.d.ts +24 -0
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -1,53 +1,35 @@
|
|
|
1
1
|
# create-request
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/create-request)
|
|
4
|
-
[](https://github.com/
|
|
4
|
+
[](https://github.com/DanielAmenou/create-request/blob/main/LICENSE)
|
|
5
5
|
[](https://bundlephobia.com/package/create-request)
|
|
6
6
|
|
|
7
7
|
`create-request` is a modern TypeScript library that transforms how you make API calls. Built as an elegant wrapper around the native Fetch API, it provides a chainable, fluent interface that dramatically reduces boilerplate while adding powerful features like automatic retries, timeout handling, and comprehensive error management.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Core Features
|
|
10
|
+
|
|
11
|
+
- ⛓️ **Chainable API** - Build and execute requests with a fluent interface
|
|
12
|
+
- ⏱️ **Timeout Support** - Set timeouts for any request
|
|
13
|
+
- 🔁 **Automatic Retries** - Retry failed requests with customizable settings
|
|
14
|
+
- 🔐 **Auth Helpers** - Simple methods for common authentication patterns
|
|
15
|
+
- 📦 **Typed Responses** - Full TypeScript support for response data
|
|
16
|
+
- 🚧 **Error Handling** - Detailed error info with custom error class
|
|
10
17
|
|
|
11
18
|
## Why create-request?
|
|
12
19
|
|
|
13
|
-
**You've probably been here before:** writing boilerplate fetch code, handling retries manually, struggling with timeouts, or wrestling with TypeScript types for your API responses. `create-request` solves all of that with an elegant
|
|
20
|
+
**You've probably been here before:** writing boilerplate fetch code, handling retries manually, struggling with timeouts, or wrestling with TypeScript types for your API responses. `create-request` solves all of that with an elegant API that separates request building from execution:
|
|
14
21
|
|
|
15
22
|
```typescript
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
const users = await create.get()
|
|
23
|
+
// Create a request
|
|
24
|
+
const usersRequest = create.get()
|
|
19
25
|
.withTimeout(5000)
|
|
20
26
|
.withRetries(3)
|
|
21
|
-
.withBearerToken('your-token')
|
|
22
|
-
.sendTo('https://api.example.com/users')
|
|
23
|
-
.json<User[]>(); // Fully typed response!
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## 🚀 Designed for Developer Happiness
|
|
27
|
-
|
|
28
|
-
- **Write Less Code** - Accomplish in one line what might take dozens with raw fetch
|
|
29
|
-
- **Fewer Bugs** - Strong typing and smart defaults prevent common API bugs
|
|
30
|
-
- **Self-Documenting** - Chainable API clearly expresses intent for easier code reviews
|
|
31
|
-
- **Universal** - Works the same in browser and Node.js environments
|
|
32
|
-
|
|
33
|
-
## Overview
|
|
34
|
-
|
|
35
|
-
`create-request` provides a chainable, fluent API for making HTTP requests with built-in solutions for the most common API challenges. It's designed for developers who value clean code, type safety, and robust error handling.
|
|
36
|
-
|
|
37
|
-
## Features
|
|
27
|
+
.withBearerToken('your-token');
|
|
38
28
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
- 🔒 **Auth Helpers** - One-liner methods for common auth patterns
|
|
44
|
-
- 🧩 **Query Parameter Management** - Easy query parameter handling with arrays support
|
|
45
|
-
- 📦 **Response Transformations** - Parse responses as JSON, text, blob, etc.
|
|
46
|
-
- 🚫 **Robust Error Handling** - Detailed error information with custom error class
|
|
47
|
-
- 🔌 **Zero Dependencies** - Built on the native Fetch API with no external baggage
|
|
48
|
-
- 🌐 **Universal** - Works exactly the same in all modern browsers and Node.js
|
|
49
|
-
- 🧠 **Smart Content-Type** - Automatic content type detection for request bodies
|
|
50
|
-
- 🏷️ **Type Safety** - Enums for all string constants to prevent typos
|
|
29
|
+
// Execute the request
|
|
30
|
+
const users = await usersRequest.sendTo('https://api.example.com/users')
|
|
31
|
+
.getJson<User[]>();
|
|
32
|
+
```
|
|
51
33
|
|
|
52
34
|
## Installation
|
|
53
35
|
|
|
@@ -61,407 +43,261 @@ Or with yarn:
|
|
|
61
43
|
yarn add create-request
|
|
62
44
|
```
|
|
63
45
|
|
|
64
|
-
##
|
|
46
|
+
## 🔄 Fetch API Comparison
|
|
65
47
|
|
|
66
|
-
###
|
|
48
|
+
### Fetch API
|
|
67
49
|
|
|
68
50
|
```typescript
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
.
|
|
72
|
-
.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
51
|
+
// Basic GET request with fetch
|
|
52
|
+
try {
|
|
53
|
+
const response = await fetch('https://api.example.com/users');
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
throw new Error(`HTTP error ${response.status}`);
|
|
56
|
+
}
|
|
57
|
+
const users = await response.json();
|
|
58
|
+
console.log(users);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error('Error fetching users:', error);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// POST request with fetch
|
|
64
|
+
try {
|
|
65
|
+
const response = await fetch('https://api.example.com/users', {
|
|
66
|
+
method: 'POST',
|
|
67
|
+
headers: {
|
|
68
|
+
'Content-Type': 'application/json',
|
|
69
|
+
'Authorization': 'Bearer token123'
|
|
70
|
+
},
|
|
71
|
+
body: JSON.stringify({ name: 'John Doe', email: 'john@example.com' })
|
|
85
72
|
});
|
|
73
|
+
if (!response.ok) {
|
|
74
|
+
throw new Error(`HTTP error ${response.status}`);
|
|
75
|
+
}
|
|
76
|
+
const result = await response.json();
|
|
77
|
+
console.log(result);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error('Error creating user:', error);
|
|
80
|
+
}
|
|
86
81
|
```
|
|
87
82
|
|
|
88
|
-
###
|
|
83
|
+
### create-request API
|
|
89
84
|
|
|
90
85
|
```typescript
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
86
|
+
// Basic GET request with create-request
|
|
87
|
+
try {
|
|
88
|
+
const users = await create.get().sendTo('https://api.example.com/users').getJson();
|
|
89
|
+
console.log(users);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error('Error fetching users:', error.message);
|
|
95
92
|
}
|
|
96
93
|
|
|
97
|
-
//
|
|
98
|
-
const
|
|
99
|
-
.
|
|
100
|
-
.
|
|
101
|
-
|
|
102
|
-
// No more type casting or guessing - your IDE autocomplete works perfectly
|
|
103
|
-
users.forEach(user => console.log(user.name));
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### 3. Request Retries Made Simple
|
|
107
|
-
|
|
108
|
-
```typescript
|
|
109
|
-
// Without create-request: Pages of manual retry logic with delay calculations
|
|
110
|
-
// With create-request: One line
|
|
94
|
+
// POST request with create-request
|
|
95
|
+
const createUserRequest = create.post()
|
|
96
|
+
.withBody({ name: 'John Doe', email: 'john@example.com' })
|
|
97
|
+
.withBearerToken('token123');
|
|
111
98
|
|
|
112
|
-
|
|
113
|
-
.
|
|
114
|
-
.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
.json();
|
|
99
|
+
try {
|
|
100
|
+
const result = await createUserRequest.sendTo('https://api.example.com/users').getJson();
|
|
101
|
+
console.log(result);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error('Error creating user:', error.message);
|
|
104
|
+
}
|
|
119
105
|
```
|
|
120
106
|
|
|
121
107
|
## Basic Usage
|
|
122
108
|
|
|
109
|
+
### Creating Requests
|
|
110
|
+
|
|
123
111
|
```typescript
|
|
124
112
|
import create from 'create-request';
|
|
125
113
|
|
|
126
|
-
//
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
.withBody({ name: 'Daniel Amenou', email: 'daniel@example.com' })
|
|
135
|
-
.withBearerToken('your-token-here')
|
|
136
|
-
.sendTo('https://api.example.com/users')
|
|
137
|
-
.json();
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
## API Reference
|
|
141
|
-
|
|
142
|
-
### Request Creation
|
|
143
|
-
|
|
144
|
-
Create requests using the appropriate factory method:
|
|
145
|
-
|
|
146
|
-
```typescript
|
|
147
|
-
// Methods without body
|
|
148
|
-
create.get()
|
|
149
|
-
create.del()
|
|
150
|
-
create.head()
|
|
151
|
-
create.options()
|
|
152
|
-
|
|
153
|
-
// Methods with body
|
|
154
|
-
create.put()
|
|
155
|
-
create.post()
|
|
156
|
-
create.patch()
|
|
114
|
+
// Create different request types
|
|
115
|
+
const getRequest = create.get();
|
|
116
|
+
const postRequest = create.post();
|
|
117
|
+
const putRequest = create.put();
|
|
118
|
+
const headRequest = create.head();
|
|
119
|
+
const deleteRequest = create.del();
|
|
120
|
+
const patchRequest = create.patch();
|
|
121
|
+
const optionsRequest = create.options();
|
|
157
122
|
```
|
|
158
123
|
|
|
159
124
|
### Request Configuration
|
|
160
125
|
|
|
161
|
-
All requests support these configuration methods:
|
|
162
|
-
|
|
163
|
-
#### Common Settings
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
import { RequestPriority, CredentialsPolicy, RequestMode, RedirectMode } from 'create-request';
|
|
167
|
-
|
|
168
|
-
// Set request headers
|
|
169
|
-
.withHeaders({ 'X-API-Key': 'abc123' })
|
|
170
|
-
|
|
171
|
-
// Set cookies
|
|
172
|
-
.withCookies({
|
|
173
|
-
sessionId: 'abc123',
|
|
174
|
-
preference: 'darkMode',
|
|
175
|
-
region: 'us-east'
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
// Set a single content type header
|
|
179
|
-
.withContentType('application/json')
|
|
180
|
-
|
|
181
|
-
// Set request timeout in milliseconds
|
|
182
|
-
.withTimeout(5000)
|
|
183
|
-
|
|
184
|
-
// Configure retry behavior
|
|
185
|
-
.withRetries(3)
|
|
186
|
-
.onRetry(({ retryCount, error }) => {
|
|
187
|
-
console.log(`Retry ${retryCount} after error: ${error.message}`);
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
// Use an external abort controller
|
|
191
|
-
.withAbortController(myAbortController)
|
|
192
|
-
|
|
193
|
-
// Set credentials policy - uses same-origin by default
|
|
194
|
-
.withCredentials(CredentialsPolicy.INCLUDE)
|
|
195
|
-
|
|
196
|
-
// Set redirect behavior
|
|
197
|
-
.withRedirect(RedirectMode.FOLLOW)
|
|
198
|
-
|
|
199
|
-
// Set request mode
|
|
200
|
-
.withMode(RequestMode.CORS)
|
|
201
|
-
|
|
202
|
-
// Set referrer
|
|
203
|
-
.withReferrer('https://example.com')
|
|
204
|
-
|
|
205
|
-
// Set keepalive flag (allows request to outlive the page)
|
|
206
|
-
.withKeepAlive(true)
|
|
207
|
-
|
|
208
|
-
// Set request priority
|
|
209
|
-
.withPriority(RequestPriority.HIGH)
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
#### Query Parameters
|
|
213
|
-
|
|
214
126
|
```typescript
|
|
215
|
-
|
|
216
|
-
.withQueryParams({
|
|
217
|
-
search: 'keyword',
|
|
218
|
-
page: 1,
|
|
219
|
-
filters: ['active', 'verified']
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
// Add a single query parameter
|
|
223
|
-
.withQueryParam('sort', 'desc')
|
|
127
|
+
import { RequestPriority, CredentialsPolicy } from 'create-request';
|
|
224
128
|
|
|
225
|
-
|
|
129
|
+
// Configure request options
|
|
130
|
+
const request = create.get()
|
|
131
|
+
// Headers
|
|
132
|
+
.withHeaders({ 'X-API-Key': 'abc123' })
|
|
226
133
|
|
|
227
|
-
|
|
134
|
+
// Timeout and retries
|
|
135
|
+
.withTimeout(5000)
|
|
136
|
+
.withRetries(3)
|
|
137
|
+
.onRetry(({ attempt, error }) => {
|
|
138
|
+
console.log(`Attempt ${attempt} failed: ${error.message}`);
|
|
139
|
+
})
|
|
228
140
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
.withBasicAuth('username', 'password')
|
|
141
|
+
// Authentication
|
|
142
|
+
.withBearerToken('your-token')
|
|
232
143
|
|
|
233
|
-
//
|
|
234
|
-
.
|
|
144
|
+
// Query parameters
|
|
145
|
+
.withQueryParams({ search: 'term', page: 1 })
|
|
235
146
|
|
|
236
|
-
//
|
|
237
|
-
.
|
|
147
|
+
// Advanced options
|
|
148
|
+
.withCredentials(CredentialsPolicy.INCLUDE)
|
|
149
|
+
.withPriority(RequestPriority.HIGH);
|
|
238
150
|
```
|
|
239
151
|
|
|
240
|
-
###
|
|
241
|
-
|
|
242
|
-
For POST, PUT, and PATCH requests, you can set a body:
|
|
152
|
+
### Request Bodies (POST/PUT/PATCH)
|
|
243
153
|
|
|
244
154
|
```typescript
|
|
245
|
-
// JSON body
|
|
246
|
-
|
|
155
|
+
// JSON body
|
|
156
|
+
const jsonRequest = create.post()
|
|
157
|
+
.withBody({ name: 'John', age: 30 });
|
|
247
158
|
|
|
248
159
|
// String body
|
|
249
|
-
.
|
|
250
|
-
|
|
251
|
-
// FormData
|
|
252
|
-
const form = new FormData();
|
|
253
|
-
form.append('file', fileBlob);
|
|
254
|
-
.withBody(form)
|
|
255
|
-
|
|
256
|
-
// Blob body
|
|
257
|
-
const blob = new Blob(['Hello, world!'], { type: 'text/plain' });
|
|
258
|
-
const request = create.post()
|
|
259
|
-
.withBody(blob)
|
|
260
|
-
.sendTo('https://api.example.com/upload');
|
|
160
|
+
const textRequest = create.post()
|
|
161
|
+
.withBody('Plain text content');
|
|
261
162
|
|
|
262
|
-
//
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
.sendTo('https://api.example.com/upload');
|
|
267
|
-
|
|
268
|
-
// ReadableStream body
|
|
269
|
-
const stream = new ReadableStream();
|
|
270
|
-
const request = create.post()
|
|
271
|
-
.withBody(stream)
|
|
272
|
-
.sendTo('https://api.example.com/upload');
|
|
163
|
+
// Form data
|
|
164
|
+
const formData = new FormData();
|
|
165
|
+
formData.append('name', 'John');
|
|
166
|
+
formData.append('file', fileBlob);
|
|
273
167
|
|
|
168
|
+
const formRequest = create.post()
|
|
169
|
+
.withBody(formData);
|
|
274
170
|
```
|
|
275
171
|
|
|
276
|
-
###
|
|
277
|
-
|
|
278
|
-
The library provides convenient methods for handling responses that can be chained directly after `sendTo()`:
|
|
172
|
+
### Executing Requests
|
|
279
173
|
|
|
280
174
|
```typescript
|
|
281
|
-
//
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
// Get as blob
|
|
292
|
-
const blob = await create.get()
|
|
293
|
-
.sendTo('https://api.example.com/file')
|
|
294
|
-
.blob();
|
|
295
|
-
|
|
296
|
-
// Get as ArrayBuffer
|
|
297
|
-
const buffer = await create.get()
|
|
298
|
-
.sendTo('https://api.example.com/binary')
|
|
299
|
-
.arrayBuffer();
|
|
300
|
-
|
|
301
|
-
// Get as ReadableStream
|
|
302
|
-
const stream = await create.get()
|
|
303
|
-
.sendTo('https://api.example.com/stream')
|
|
304
|
-
.body();
|
|
305
|
-
|
|
306
|
-
// For more control, you can access the raw response first
|
|
307
|
-
const response = await create.get().sendTo('https://api.example.com/data');
|
|
308
|
-
const status = response.status;
|
|
309
|
-
const headers = response.headers;
|
|
310
|
-
const data = await response.json();
|
|
175
|
+
// Simple execution
|
|
176
|
+
const response = await request.sendTo('https://api.example.com/endpoint');
|
|
177
|
+
|
|
178
|
+
// With direct data extraction
|
|
179
|
+
const jsonData = await request.sendTo('https://api.example.com/endpoint').getJson();
|
|
180
|
+
const textData = await request.sendTo('https://api.example.com/endpoint').getText();
|
|
181
|
+
const blobData = await request.sendTo('https://api.example.com/endpoint').getBlob();
|
|
182
|
+
const bodyStream = await request.sendTo('https://api.example.com/endpoint').getBody();
|
|
183
|
+
const arrayBuffer = await request.sendTo('https://api.example.com/endpoint').getArrayBuffer();
|
|
311
184
|
```
|
|
312
185
|
|
|
313
186
|
### Error Handling
|
|
314
187
|
|
|
315
|
-
|
|
188
|
+
All errors from requests are instances of `RequestError` with detailed information:
|
|
316
189
|
|
|
317
190
|
```typescript
|
|
318
191
|
try {
|
|
319
|
-
const data = await
|
|
320
|
-
.sendTo('https://api.example.com/data')
|
|
321
|
-
.json();
|
|
192
|
+
const data = await request.sendTo('https://api.example.com/data').getJson();
|
|
322
193
|
} catch (error) {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
194
|
+
// error will always be a RequestError
|
|
195
|
+
console.log(error.message); // Error message
|
|
196
|
+
console.log(error.status); // HTTP status code (if available)
|
|
197
|
+
console.log(error.url); // Request URL
|
|
198
|
+
console.log(error.method); // HTTP method
|
|
199
|
+
console.log(error.timeoutError); // Whether it was a timeout
|
|
200
|
+
|
|
201
|
+
// Access the original response if available
|
|
202
|
+
if (error.response) {
|
|
203
|
+
// Raw Response object is available
|
|
204
|
+
console.log(error.response.status);
|
|
330
205
|
}
|
|
331
206
|
}
|
|
332
207
|
```
|
|
333
208
|
|
|
334
209
|
## Advanced Usage
|
|
335
210
|
|
|
336
|
-
###
|
|
211
|
+
### Request Reuse
|
|
337
212
|
|
|
338
213
|
```typescript
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
.
|
|
342
|
-
.
|
|
343
|
-
|
|
344
|
-
const url = window.URL.createObjectURL(blob);
|
|
345
|
-
|
|
346
|
-
// Create a download link
|
|
347
|
-
const a = document.createElement('a');
|
|
348
|
-
a.href = url;
|
|
349
|
-
a.download = 'report.pdf';
|
|
350
|
-
a.click();
|
|
214
|
+
// Create a base authenticated request
|
|
215
|
+
const authRequest = create.get()
|
|
216
|
+
.withBearerToken('token123')
|
|
217
|
+
.withTimeout(5000)
|
|
218
|
+
.withRetries(2);
|
|
351
219
|
|
|
352
|
-
//
|
|
353
|
-
|
|
220
|
+
// Reuse for different endpoints
|
|
221
|
+
const users = await authRequest.sendTo('https://api.example.com/users').getJson();
|
|
222
|
+
const products = await authRequest.sendTo('https://api.example.com/products').getJson();
|
|
354
223
|
```
|
|
355
224
|
|
|
356
|
-
###
|
|
225
|
+
### Request Cancellation
|
|
357
226
|
|
|
358
227
|
```typescript
|
|
359
228
|
const controller = new AbortController();
|
|
360
229
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
.withAbortController(controller)
|
|
365
|
-
.sendTo('https://api.example.com/data')
|
|
366
|
-
.json();
|
|
367
|
-
} catch (error) {
|
|
368
|
-
// Handle the aborted request
|
|
369
|
-
}
|
|
230
|
+
const request = create.get()
|
|
231
|
+
.withTimeout(10000)
|
|
232
|
+
.withAbortController(controller);
|
|
370
233
|
|
|
371
|
-
//
|
|
234
|
+
// Later, cancel the request if needed
|
|
372
235
|
setTimeout(() => controller.abort(), 2000);
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
### Request Priority
|
|
376
236
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
//
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
.sendTo('https://api.example.com/user/profile')
|
|
384
|
-
.json();
|
|
385
|
-
|
|
386
|
-
// Low priority for non-critical resources
|
|
387
|
-
const recommendations = await create.get()
|
|
388
|
-
.withPriority(RequestPriority.LOW)
|
|
389
|
-
.sendTo('https://api.example.com/recommendations')
|
|
390
|
-
.json();
|
|
237
|
+
try {
|
|
238
|
+
const data = await request.sendTo('https://api.example.com/slow-endpoint').getJson();
|
|
239
|
+
} catch (error) {
|
|
240
|
+
// Check if request was cancelled
|
|
241
|
+
console.log('Request was cancelled:', error.name === 'AbortError');
|
|
242
|
+
}
|
|
391
243
|
```
|
|
392
244
|
|
|
393
|
-
###
|
|
245
|
+
### Working with Typed Responses
|
|
394
246
|
|
|
395
247
|
```typescript
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
.withBearerToken(token)
|
|
401
|
-
.withHeaders({
|
|
402
|
-
'X-App-Version': '1.0.0',
|
|
403
|
-
})
|
|
404
|
-
.withTimeout(10000)
|
|
405
|
-
.withRetries(2)
|
|
406
|
-
.withCredentials(CredentialsPolicy.INCLUDE)
|
|
407
|
-
.withPriority(RequestPriority.HIGH);
|
|
248
|
+
interface User {
|
|
249
|
+
id: number;
|
|
250
|
+
name: string;
|
|
251
|
+
email: string;
|
|
408
252
|
}
|
|
409
253
|
|
|
410
|
-
|
|
411
|
-
const
|
|
412
|
-
.
|
|
413
|
-
|
|
254
|
+
const userRequest = create.get();
|
|
255
|
+
const user = await userRequest.sendTo('https://api.example.com/user/123')
|
|
256
|
+
.getJson<User>();
|
|
257
|
+
|
|
258
|
+
// TypeScript knows the type
|
|
259
|
+
console.log(user.name);
|
|
414
260
|
```
|
|
415
261
|
|
|
416
|
-
###
|
|
262
|
+
### Promise Chaining
|
|
417
263
|
|
|
418
264
|
```typescript
|
|
419
|
-
|
|
420
|
-
const response = await create.get()
|
|
421
|
-
.withCookies({
|
|
422
|
-
sessionId: 'abc123',
|
|
423
|
-
theme: 'dark',
|
|
424
|
-
region: 'us-east',
|
|
425
|
-
'analytics-opt-in': 'true'
|
|
426
|
-
})
|
|
427
|
-
.sendTo('https://api.example.com/dashboard');
|
|
265
|
+
const request = create.get();
|
|
428
266
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
267
|
+
request.sendTo('https://api.example.com/data')
|
|
268
|
+
.then(response => {
|
|
269
|
+
console.log('Status:', response.status);
|
|
270
|
+
return response.getJson();
|
|
271
|
+
})
|
|
272
|
+
.then(data => {
|
|
273
|
+
console.log('Data:', data);
|
|
274
|
+
})
|
|
275
|
+
.catch(error => {
|
|
276
|
+
console.error('Error:', error.message);
|
|
277
|
+
});
|
|
434
278
|
```
|
|
435
279
|
|
|
436
|
-
##
|
|
437
|
-
|
|
438
|
-
### Browser Limitations
|
|
439
|
-
|
|
440
|
-
1. **CORS Restrictions** - Browsers enforce Same-Origin Policy and CORS. Requests to different origins must have proper CORS headers set up server-side.
|
|
441
|
-
|
|
442
|
-
2. **Cookies and Authentication** - Third-party cookies might be blocked depending on browser settings. Use `withCredentials(CredentialsPolicy.INCLUDE)` for cross-origin authenticated requests.
|
|
443
|
-
|
|
444
|
-
3. **Mixed Content** - Browsers block HTTP requests from HTTPS pages. Always use HTTPS endpoints in production.
|
|
445
|
-
|
|
446
|
-
4. **Content Security Policy (CSP)** - If your application uses CSP, you must configure it to allow connections to your API endpoints.
|
|
447
|
-
|
|
448
|
-
5. **Priority Hints** - The `withPriority` feature is only supported in some modern browsers and may be ignored in others.
|
|
449
|
-
|
|
450
|
-
6. **KeepAlive** - The `withKeepAlive` feature allows requests to outlive the page but has varying support across browsers.
|
|
280
|
+
## CSRF Protection
|
|
451
281
|
|
|
452
|
-
###
|
|
282
|
+
### Global CSRF Configuration
|
|
453
283
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
284
|
+
```typescript
|
|
285
|
+
// Configure CSRF settings for all requests
|
|
286
|
+
create.config.setCsrfToken('your-csrf-token');
|
|
287
|
+
create.config.setCsrfHeaderName('X-CSRF-Token');
|
|
288
|
+
create.config.setXsrfCookieName('XSRF-TOKEN');
|
|
289
|
+
```
|
|
459
290
|
|
|
460
|
-
|
|
291
|
+
### Per-Request CSRF Settings
|
|
461
292
|
|
|
462
|
-
|
|
293
|
+
```typescript
|
|
294
|
+
// Configure CSRF for a specific request
|
|
295
|
+
const request = create.post()
|
|
296
|
+
.withCsrfToken('request-specific-token')
|
|
297
|
+
.withoutCsrfProtection(); // Disable automatic CSRF protection
|
|
298
|
+
```
|
|
463
299
|
|
|
464
|
-
## Browser
|
|
300
|
+
## Browser Support
|
|
465
301
|
|
|
466
302
|
This library works with all browsers that support the Fetch API:
|
|
467
303
|
|
|
@@ -471,105 +307,6 @@ This library works with all browsers that support the Fetch API:
|
|
|
471
307
|
- Edge 14+
|
|
472
308
|
- Opera 29+
|
|
473
309
|
|
|
474
|
-
## Comparison with Other Libraries
|
|
475
|
-
|
|
476
|
-
| Feature | create-request | axios | fetch |
|
|
477
|
-
|---------|---------------|-------|-------|
|
|
478
|
-
| Bundle Size | Small (~2KB) | Medium (~14KB) | Smallest (built-in) |
|
|
479
|
-
| TypeScript Support | Full with type inference | Partial | Manual |
|
|
480
|
-
| Type Safety | Enums for constants | Limited | None |
|
|
481
|
-
| Chainable API | ✅ Yes | ❌ No | ❌ No |
|
|
482
|
-
| Request Cancellation | ✅ Yes (AbortController) | ✅ Yes | ✅ Yes (manual) |
|
|
483
|
-
| Auto JSON | ✅ Yes | ✅ Yes | ❌ No |
|
|
484
|
-
| Timeout | ✅ Yes | ✅ Yes | ❌ No (manual) |
|
|
485
|
-
| Retries | ✅ Yes | ❌ No (needs addon) | ❌ No (manual) |
|
|
486
|
-
| Query params with arrays | ✅ Yes | ✅ Yes | ❌ No (manual) |
|
|
487
|
-
| Request Priority | ✅ Yes (simple API) | ❌ No | ✅ Yes (via options) |
|
|
488
|
-
| KeepAlive | ✅ Yes (simple API) | ❌ No | ✅ Yes (via options) |
|
|
489
|
-
| Learning Curve | Low | Medium | Medium |
|
|
490
|
-
|
|
491
|
-
### Why Not Just Use fetch?
|
|
492
|
-
like JSON parsing
|
|
493
|
-
The native Fetch API is powerful but low-level, requiring you to:ing
|
|
494
|
-
- Write boilerplate for common tasks like JSON parsing
|
|
495
|
-
- Manually implement timeout handlingeps
|
|
496
|
-
- Create your own retry mechanisms- Parse non-2xx responses manually
|
|
497
|
-
- Handle errors across multiple steps
|
|
498
|
-
- Parse non-2xx responses manually`create-request` gives you all these features with a cleaner API that's designed specifically for modern TypeScript applications.
|
|
499
|
-
|
|
500
|
-
`create-request` gives you all these features with a cleaner API that's designed specifically for modern TypeScript applications.### Why Not axios?
|
|
501
|
-
|
|
502
|
-
### Why Not axios?est` offers:
|
|
503
|
-
|
|
504
|
-
While axios is popular, `create-request` offers:er)
|
|
505
|
-
- Smaller bundle size (~85% smaller)n
|
|
506
|
-
- More complete TypeScript integration
|
|
507
|
-
- Built-in retries without addons- Modern features like priority hints
|
|
508
|
-
- Modern features like priority hintsainable API
|
|
509
|
-
- A more intuitive, chainable API
|
|
510
|
-
|
|
511
|
-
## Real-world Examples
|
|
512
|
-
t for Authentication
|
|
513
|
-
### API Client for Authentication
|
|
514
|
-
|
|
515
|
-
```typescripta reusable authentication client
|
|
516
|
-
// Create a reusable authentication client
|
|
517
|
-
function createAuthClient(baseUrl) {
|
|
518
|
-
return {{
|
|
519
|
-
login: async (email, password) => {
|
|
520
|
-
return create.post()
|
|
521
|
-
.withBody({ email, password })eout(3000)
|
|
522
|
-
.withTimeout(3000) .sendTo(`${baseUrl}/auth/login`)
|
|
523
|
-
.sendTo(`${baseUrl}/auth/login`) .json();
|
|
524
|
-
.json();
|
|
525
|
-
},
|
|
526
|
-
en) => {
|
|
527
|
-
refreshToken: async (refreshToken) => {t()
|
|
528
|
-
return create.post()
|
|
529
|
-
.withBody({ refreshToken })ries(2)
|
|
530
|
-
.withRetries(2) .sendTo(`${baseUrl}/auth/refresh`)
|
|
531
|
-
.sendTo(`${baseUrl}/auth/refresh`) .json();
|
|
532
|
-
.json(); }
|
|
533
|
-
} };
|
|
534
|
-
};
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
// Use it in your applicationst authClient = createAuthClient('https://api.example.com');
|
|
538
|
-
const authClient = createAuthClient('https://api.example.com');const { token, user } = await authClient.login('user@example.com', 'password');
|
|
539
|
-
const { token, user } = await authClient.login('user@example.com', 'password');
|
|
540
|
-
```
|
|
541
|
-
ad with Progress
|
|
542
|
-
### File Upload with Progress
|
|
543
|
-
|
|
544
|
-
```typescript
|
|
545
|
-
// Upload a file with abort capabilityconst uploadFile = async (file, onProgress) => {
|
|
546
|
-
const uploadFile = async (file, onProgress) => {Controller();
|
|
547
|
-
const controller = new AbortController();
|
|
548
|
-
const form = new FormData();
|
|
549
|
-
const form = new FormData();append('file', file);
|
|
550
|
-
form.append('file', file);
|
|
551
|
-
|
|
552
|
-
try {
|
|
553
|
-
return await create.post()
|
|
554
|
-
.withBody(form)oller(controller)
|
|
555
|
-
.withAbortController(controller)or large files
|
|
556
|
-
.withTimeout(60000) // 1 minute timeout for large filesries(2)
|
|
557
|
-
.withRetries(2)s://api.example.com/upload')
|
|
558
|
-
.sendTo('https://api.example.com/upload')
|
|
559
|
-
.json();
|
|
560
|
-
} catch (error) {f (error instanceof RequestError) {
|
|
561
|
-
if (error instanceof RequestError) {ror(`Upload failed: ${error.message}`);
|
|
562
|
-
console.error(`Upload failed: ${error.message}`); }
|
|
563
|
-
} throw error;
|
|
564
|
-
throw error;
|
|
565
|
-
}
|
|
566
|
-
turn {
|
|
567
|
-
return { abort: () => controller.abort()
|
|
568
|
-
abort: () => controller.abort();
|
|
569
|
-
};};
|
|
570
|
-
};
|
|
571
|
-
```
|
|
572
|
-
|
|
573
310
|
## License
|
|
574
311
|
|
|
575
312
|
MIT
|