create-request 0.0.1-beta.13 → 0.0.1-beta.14

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.
Files changed (2) hide show
  1. package/README.md +120 -127
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -6,6 +6,17 @@
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
+ ## Table of Contents
10
+
11
+ - [Core Features](#core-features)
12
+ - [Why create-request](#why-create-request)
13
+ - [Installation](#installation)
14
+ - [Basic Usage](#basic-usage)
15
+ - [Advanced Usage](#advanced-usage)
16
+ - [CSRF Protection](#csrf-protection)
17
+ - [Browser Support](#browser-support)
18
+ - [License](#license)
19
+
9
20
  ## Core Features
10
21
 
11
22
  - 🚀 **Performance** - Tiny bundle size with zero dependencies
@@ -29,13 +40,13 @@
29
40
  // Before: Regular fetch
30
41
  async function createUser(userData) {
31
42
  try {
32
- const response = await fetch('https://api.example.com/users', {
33
- method: 'POST',
43
+ const response = await fetch("https://api.example.com/users", {
44
+ method: "POST",
34
45
  headers: {
35
- 'Content-Type': 'application/json',
36
- 'Authorization': 'Basic ' + btoa('username:password')
46
+ "Content-Type": "application/json",
47
+ Authorization: "Basic " + btoa("username:password"),
37
48
  },
38
- body: JSON.stringify(userData)
49
+ body: JSON.stringify(userData),
39
50
  });
40
51
 
41
52
  if (!response.ok) {
@@ -44,22 +55,23 @@ async function createUser(userData) {
44
55
  const data = await response.json();
45
56
  return data;
46
57
  } catch (error) {
47
- console.error('Fetch error:', error);
58
+ console.error("Fetch error:", error);
48
59
  throw error;
49
60
  }
50
61
  }
51
62
 
52
63
  // After: With create-request
53
- import create from 'create-request';
64
+ import create from "create-request";
54
65
 
55
66
  function createUser(userData) {
56
- return create.post()
57
- .withBasicAuth('username', 'password')
67
+ return create
68
+ .post()
69
+ .withBasicAuth("username", "password")
58
70
  .withBody(userData)
59
- .sendTo('https://api.example.com/users')
71
+ .sendTo("https://api.example.com/users")
60
72
  .getData<User>()
61
73
  .catch(error => {
62
- console.error('Fetch error:', error);
74
+ console.error("Fetch error:", error);
63
75
  throw error;
64
76
  });
65
77
  }
@@ -82,7 +94,7 @@ yarn add create-request
82
94
  ### Creating Requests
83
95
 
84
96
  ```typescript
85
- import create from 'create-request';
97
+ import create from "create-request";
86
98
 
87
99
  // Create different request types
88
100
  const getRequest = create.get();
@@ -99,13 +111,14 @@ const optionsRequest = create.options();
99
111
  The library provides a comprehensive set of configuration methods that can be chained together to customize your requests:
100
112
 
101
113
  ```typescript
102
- import create, { RequestPriority, CredentialsPolicy, RequestMode, CacheMode, RedirectMode, ReferrerPolicy } from 'create-request';
114
+ import create, { RequestPriority, CredentialsPolicy, RequestMode, CacheMode, RedirectMode, ReferrerPolicy } from "create-request";
103
115
 
104
116
  // Configure request options
105
- const request = create.get()
117
+ const request = create
118
+ .get()
106
119
  // Basic headers
107
- .withHeaders({ 'X-API-Key': 'abc123', 'Accept-Language': 'en-US' })
108
- .withHeader('Custom-Header', 'value') // Add a single header
120
+ .withHeaders({ "X-API-Key": "abc123", "Accept-Language": "en-US" })
121
+ .withHeader("Custom-Header", "value") // Add a single header
109
122
 
110
123
  // Timeout settings
111
124
  .withTimeout(5000) // Request will abort after 5 seconds
@@ -117,95 +130,89 @@ const request = create.get()
117
130
  })
118
131
 
119
132
  // Authentication methods
120
- .withBearerToken('your-token') // Adds Authorization: Bearer your-token
121
- .withBasicAuth('username', 'password') // HTTP Basic Authentication
133
+ .withBearerToken("your-token") // Adds Authorization: Bearer your-token
134
+ .withBasicAuth("username", "password") // HTTP Basic Authentication
122
135
 
123
136
  // URL parameters
124
- .withQueryParams({ search: 'term', page: 1, limit: 20 })
125
- .withQueryParam('filter', 'active') // Add a single query parameter
137
+ .withQueryParams({ search: "term", page: 1, limit: 20 })
138
+ .withQueryParam("filter", "active") // Add a single query parameter
126
139
 
127
140
  // Request body configuration (for POST/PUT/PATCH)
128
- .withContentType('application/json') // Set specific content type
141
+ .withContentType("application/json") // Set specific content type
129
142
 
130
143
  // Fetch API options
131
144
  .withCredentials(CredentialsPolicy.INCLUDE) // Includes cookies with cross-origin requests
132
145
  .withMode(RequestMode.CORS) // Controls CORS behavior
133
146
  .withRedirect(RedirectMode.FOLLOW) // Controls redirect behavior (follow, error, manual)
134
- .withReferrer('https://example.com') // Sets request referrer
147
+ .withReferrer("https://example.com") // Sets request referrer
135
148
  .withReferrerPolicy(ReferrerPolicy.NO_REFERRER_WHEN_DOWNGRADE) // Controls referrer policy
136
- .withPriority(RequestPriority.HIGH) // Sets request priority
149
+ .withPriority(RequestPriority.HIGH); // Sets request priority
137
150
  ```
138
151
 
139
152
  Each configuration method returns the request object, allowing for a fluent interface where methods can be chained together. You can configure only what you need for a specific request:
140
153
 
141
154
  ```typescript
142
155
  // Simple example with just what's needed
143
- const searchUsers = create.get()
144
- .withBearerToken(userToken)
145
- .withQueryParams({ q: searchTerm, limit: 20 })
146
- .withTimeout(3000);
156
+ const searchUsers = create.get().withBearerToken(userToken).withQueryParams({ q: searchTerm, limit: 20 }).withTimeout(3000);
147
157
 
148
158
  // Now execute the request
149
- const users = await searchUsers.sendTo('https://api.example.com/users').getData();
159
+ const users = await searchUsers.sendTo("https://api.example.com/users").getData();
150
160
  ```
151
161
 
152
162
  You can also create reusable base requests with common settings:
153
163
 
154
164
  ```typescript
155
165
  // Create base authenticated request
156
- const apiBase = create.get()
166
+ const apiBase = create
167
+ .get()
157
168
  .withHeaders({
158
- 'X-API-Version': '1.2',
159
- 'Accept-Language': 'en-US'
169
+ "X-API-Version": "1.2",
170
+ "Accept-Language": "en-US",
160
171
  })
161
172
  .withBearerToken(authToken)
162
173
  .withTimeout(5000)
163
174
  .withRetries(2);
164
175
 
165
176
  // Use the base request for different endpoints
166
- const users = await apiBase.sendTo('https://api.example.com/users').getData();
167
- const products = await apiBase.sendTo('https://api.example.com/products').getData();
177
+ const users = await apiBase.sendTo("https://api.example.com/users").getData();
178
+ const products = await apiBase.sendTo("https://api.example.com/products").getData();
168
179
  ```
169
180
 
170
181
  ### Request Bodies (POST/PUT/PATCH)
171
182
 
172
183
  ```typescript
173
184
  // JSON body
174
- const jsonRequest = create.post()
175
- .withBody({ name: 'John', age: 30 });
185
+ const jsonRequest = create.post().withBody({ name: "John", age: 30 });
176
186
 
177
187
  // String body
178
- const textRequest = create.post()
179
- .withBody('Plain text content');
188
+ const textRequest = create.post().withBody("Plain text content");
180
189
 
181
190
  // Form data
182
191
  const formData = new FormData();
183
- formData.append('name', 'John');
184
- formData.append('file', fileBlob);
192
+ formData.append("name", "John");
193
+ formData.append("file", fileBlob);
185
194
 
186
- const formRequest = create.post()
187
- .withBody(formData);
195
+ const formRequest = create.post().withBody(formData);
188
196
  ```
189
197
 
190
198
  ### Executing Requests
191
199
 
192
200
  ```typescript
193
201
  // Simple execution
194
- const response = await request.sendTo('https://api.example.com/endpoint');
202
+ const response = await request.sendTo("https://api.example.com/endpoint");
195
203
 
196
204
  // With direct data extraction
197
- const jsonData = await request.sendTo('https://api.example.com/endpoint').getJson();
198
- const textData = await request.sendTo('https://api.example.com/endpoint').getText();
199
- const blobData = await request.sendTo('https://api.example.com/endpoint').getBlob();
200
- const bodyStream = await request.sendTo('https://api.example.com/endpoint').getBody();
201
- const arrayBuffer = await request.sendTo('https://api.example.com/endpoint').getArrayBuffer();
205
+ const jsonData = await request.sendTo("https://api.example.com/endpoint").getJson();
206
+ const textData = await request.sendTo("https://api.example.com/endpoint").getText();
207
+ const blobData = await request.sendTo("https://api.example.com/endpoint").getBlob();
208
+ const bodyStream = await request.sendTo("https://api.example.com/endpoint").getBody();
209
+ const arrayBuffer = await request.sendTo("https://api.example.com/endpoint").getArrayBuffer();
202
210
 
203
211
  // Using the data selector API to extract specific data
204
- const userData = await request.sendTo('https://api.example.com/users')
205
- .getData(data => data.results.users);
212
+ const userData = await request.sendTo("https://api.example.com/users").getData(data => data.results.users);
206
213
 
207
214
  // Using the data selector without a selector function just returns the full JSON response
208
- const fullData = await request.sendTo('https://api.example.com/data').getData();
215
+ const fullData = await request.sendTo("https://api.example.com/data").getData();
209
216
  ```
210
217
 
211
218
  ### Data Selection
@@ -214,37 +221,27 @@ The `getData` method provides a powerful way to extract and transform specific d
214
221
 
215
222
  ```typescript
216
223
  // Extract specific properties from nested structures
217
- const posts = await request
218
- .sendTo('https://api.example.com/feed')
219
- .getData(data => data.feed.posts);
224
+ const posts = await request.sendTo("https://api.example.com/feed").getData(data => data.feed.posts);
220
225
 
221
226
  // Transform data in the selector function
222
- const usernames = await request
223
- .sendTo('https://api.example.com/users')
224
- .getData(data => data.users.map(user => user.username));
227
+ const usernames = await request.sendTo("https://api.example.com/users").getData(data => data.users.map(user => user.username));
225
228
 
226
229
  // Apply filtering in the selector
227
- const activeUsers = await request
228
- .sendTo('https://api.example.com/users')
229
- .getData(data => data.users.filter(user => user.isActive));
230
+ const activeUsers = await request.sendTo("https://api.example.com/users").getData(data => data.users.filter(user => user.isActive));
230
231
 
231
232
  // Combine data from complex nested structures
232
- const combinedData = await request
233
- .sendTo('https://api.example.com/dashboard')
234
- .getData(data => ({
235
- userCount: data.stats.users.total,
236
- recentPosts: data.content.recent.slice(0, 5),
237
- notifications: data.user.notifications.unread
238
- }));
233
+ const combinedData = await request.sendTo("https://api.example.com/dashboard").getData(data => ({
234
+ userCount: data.stats.users.total,
235
+ recentPosts: data.content.recent.slice(0, 5),
236
+ notifications: data.user.notifications.unread,
237
+ }));
239
238
  ```
240
239
 
241
240
  When a selector fails, the error message will contain the original response data to help diagnose the issue:
242
241
 
243
242
  ```typescript
244
243
  try {
245
- const result = await request
246
- .sendTo('https://api.example.com/data')
247
- .getData(data => data.results.items); // Will fail if structure is different
244
+ const result = await request.sendTo("https://api.example.com/data").getData(data => data.results.items); // Will fail if structure is different
248
245
  } catch (error) {
249
246
  console.error(error);
250
247
  // Error message includes the original response data
@@ -257,13 +254,13 @@ All errors from requests are instances of `RequestError` with detailed informati
257
254
 
258
255
  ```typescript
259
256
  try {
260
- const data = await request.sendTo('https://api.example.com/data').getJson();
257
+ const data = await request.sendTo("https://api.example.com/data").getJson();
261
258
  } catch (error) {
262
259
  // error will always be a RequestError
263
- console.log(error.message); // Error message
264
- console.log(error.status); // HTTP status code (if available)
265
- console.log(error.url); // Request URL
266
- console.log(error.method); // HTTP method
260
+ console.log(error.message); // Error message
261
+ console.log(error.status); // HTTP status code (if available)
262
+ console.log(error.url); // Request URL
263
+ console.log(error.method); // HTTP method
267
264
  console.log(error.timeoutError); // Whether it was a timeout
268
265
 
269
266
  // Access the original response if available
@@ -277,34 +274,37 @@ try {
277
274
  ### Caching Requests
278
275
 
279
276
  ```typescript
280
- import create, { createMemoryStorage, createLocalStorageStorage, createSessionStorageStorage } from 'create-request';
277
+ import create, { createMemoryStorage, createLocalStorageStorage, createSessionStorageStorage } from "create-request";
281
278
 
282
279
  // Simple in-memory caching
283
- const request = create.get()
280
+ const request = create
281
+ .get()
284
282
  .withCache({
285
283
  storage: createMemoryStorage(),
286
- ttl: 60000 // 1 minute in milliseconds
284
+ ttl: 60000, // 1 minute in milliseconds
287
285
  })
288
- .sendTo('https://api.example.com/data');
286
+ .sendTo("https://api.example.com/data");
289
287
 
290
288
  // Using localStorage storage
291
- const request = create.get()
289
+ const request = create
290
+ .get()
292
291
  .withCache({
293
292
  storage: createLocalStorageStorage(),
294
293
  ttl: 5 * 60 * 1000, // 5 minutes
295
- maxSize: '1MB',
296
- keyPrefix: 'user-data'
294
+ maxSize: "1MB",
295
+ keyPrefix: "user-data",
297
296
  })
298
- .sendTo('https://api.example.com/users');
297
+ .sendTo("https://api.example.com/users");
299
298
 
300
299
  // Using sessionStorage for per-session caching
301
- const request = create.get()
300
+ const request = create
301
+ .get()
302
302
  .withCache({
303
303
  storage: createSessionStorageStorage(),
304
304
  maxEntries: 50,
305
- varyByHeaders: ['x-api-version']
305
+ varyByHeaders: ["x-api-version"],
306
306
  })
307
- .sendTo('https://api.example.com/data');
307
+ .sendTo("https://api.example.com/data");
308
308
  ```
309
309
 
310
310
  ## Advanced Usage
@@ -313,14 +313,11 @@ const request = create.get()
313
313
 
314
314
  ```typescript
315
315
  // Create a base authenticated request
316
- const authRequest = create.get()
317
- .withBearerToken('token123')
318
- .withTimeout(5000)
319
- .withRetries(2);
316
+ const authRequest = create.get().withBearerToken("token123").withTimeout(5000).withRetries(2);
320
317
 
321
318
  // Reuse for different endpoints
322
- const users = await authRequest.sendTo('https://api.example.com/users').getJson();
323
- const products = await authRequest.sendTo('https://api.example.com/products').getJson();
319
+ const users = await authRequest.sendTo("https://api.example.com/users").getJson();
320
+ const products = await authRequest.sendTo("https://api.example.com/products").getJson();
324
321
  ```
325
322
 
326
323
  ### Request Cancellation
@@ -328,18 +325,16 @@ const products = await authRequest.sendTo('https://api.example.com/products').ge
328
325
  ```typescript
329
326
  const controller = new AbortController();
330
327
 
331
- const request = create.get()
332
- .withTimeout(10000)
333
- .withAbortController(controller);
328
+ const request = create.get().withTimeout(10000).withAbortController(controller);
334
329
 
335
330
  // Later, cancel the request if needed
336
331
  setTimeout(() => controller.abort(), 2000);
337
332
 
338
333
  try {
339
- const data = await request.sendTo('https://api.example.com/slow-endpoint').getJson();
334
+ const data = await request.sendTo("https://api.example.com/slow-endpoint").getJson();
340
335
  } catch (error) {
341
336
  // Check if request was cancelled
342
- console.log('Request was cancelled:', error.name === 'AbortError');
337
+ console.log("Request was cancelled:", error.name === "AbortError");
343
338
  }
344
339
  ```
345
340
 
@@ -357,25 +352,19 @@ interface ApiResponse {
357
352
  pagination: {
358
353
  total: number;
359
354
  page: number;
360
- }
355
+ };
361
356
  }
362
357
 
363
358
  const userRequest = create.get();
364
359
 
365
360
  // Type the full response
366
- const response = await userRequest
367
- .sendTo('https://api.example.com/users')
368
- .getJson<ApiResponse>();
361
+ const response = await userRequest.sendTo("https://api.example.com/users").getJson<ApiResponse>();
369
362
 
370
363
  // Or use getData with type parameters
371
- const users = await userRequest
372
- .sendTo('https://api.example.com/users')
373
- .getData<ApiResponse, User[]>(data => data.users);
364
+ const users = await userRequest.sendTo("https://api.example.com/users").getData<ApiResponse, User[]>(data => data.users);
374
365
 
375
366
  // Or just get the full typed response
376
- const fullData = await userRequest
377
- .sendTo('https://api.example.com/users')
378
- .getData<ApiResponse>();
367
+ const fullData = await userRequest.sendTo("https://api.example.com/users").getData<ApiResponse>();
379
368
 
380
369
  // TypeScript knows the types
381
370
  console.log(users[0].name);
@@ -386,37 +375,39 @@ console.log(users[0].name);
386
375
  ```typescript
387
376
  const request = create.get();
388
377
 
389
- request.sendTo('https://api.example.com/data')
378
+ request
379
+ .sendTo("https://api.example.com/data")
390
380
  .then(response => {
391
- console.log('Status:', response.status);
381
+ console.log("Status:", response.status);
392
382
  return response.getJson();
393
383
  })
394
384
  .then(data => {
395
- console.log('Data:', data);
385
+ console.log("Data:", data);
396
386
  })
397
387
  .catch(error => {
398
- console.error('Error:', error.message);
388
+ console.error("Error:", error.message);
399
389
  });
400
390
  ```
401
391
 
402
392
  ### Advanced Caching
403
393
 
404
394
  ```typescript
405
- import create, { createMemoryStorage, StorageProvider } from 'create-request';
395
+ import create, { createMemoryStorage, StorageProvider } from "create-request";
406
396
 
407
397
  // Custom key generation
408
- const request = create.get()
398
+ const request = create
399
+ .get()
409
400
  .withCache({
410
401
  storage: createMemoryStorage(),
411
402
  keyGenerator: (url, method, headers) => {
412
403
  // Include user ID from authorization header in the cache key
413
- const authHeader = headers?.['Authorization'] || '';
404
+ const authHeader = headers?.["Authorization"] || "";
414
405
  const userMatch = authHeader.match(/User-(\d+)/);
415
- const userId = userMatch ? userMatch[1] : 'anonymous';
406
+ const userId = userMatch ? userMatch[1] : "anonymous";
416
407
  return `${method}:${userId}:${url}`;
417
- }
408
+ },
418
409
  })
419
- .sendTo('https://api.example.com/data');
410
+ .sendTo("https://api.example.com/data");
420
411
  ```
421
412
 
422
413
  ### Implementing Custom Storage Providers
@@ -424,7 +415,7 @@ const request = create.get()
424
415
  You can create your own storage provider by implementing the `StorageProvider` interface:
425
416
 
426
417
  ```typescript
427
- import { StorageProvider } from 'create-request';
418
+ import { StorageProvider } from "create-request";
428
419
 
429
420
  // Create a simple custom storage provider
430
421
  export function createNamespacedStorage(namespace: string): StorageProvider {
@@ -461,17 +452,18 @@ export function createNamespacedStorage(namespace: string): StorageProvider {
461
452
  Object.keys(localStorage)
462
453
  .filter(key => key.startsWith(`${namespace}:`))
463
454
  .forEach(key => localStorage.removeItem(key));
464
- }
455
+ },
465
456
  };
466
457
  }
467
458
 
468
459
  // Usage:
469
- const request = create.get()
460
+ const request = create
461
+ .get()
470
462
  .withCache({
471
- storage: createNamespacedStorage('api-cache'),
472
- ttl: 24 * 60 * 60 * 1000 // 24 hours
463
+ storage: createNamespacedStorage("api-cache"),
464
+ ttl: 24 * 60 * 60 * 1000, // 24 hours
473
465
  })
474
- .sendTo('https://api.example.com/data');
466
+ .sendTo("https://api.example.com/data");
475
467
  ```
476
468
 
477
469
  With custom storage providers, you can integrate with any storage system, such as:
@@ -502,9 +494,9 @@ You can configure CSRF settings globally for all requests:
502
494
 
503
495
  ```typescript
504
496
  // Configure CSRF settings for all requests
505
- create.config.setCsrfToken('your-csrf-token');
506
- create.config.setCsrfHeaderName('X-CSRF-Token'); // Default header name
507
- create.config.setXsrfCookieName('XSRF-TOKEN'); // Default cookie name
497
+ create.config.setCsrfToken("your-csrf-token");
498
+ create.config.setCsrfHeaderName("X-CSRF-Token"); // Default header name
499
+ create.config.setXsrfCookieName("XSRF-TOKEN"); // Default cookie name
508
500
  create.config.setEnableAntiCsrf(true); // Enable/disable X-Requested-With header
509
501
  create.config.setEnableAutoXsrf(true); // Enable/disable automatic cookie-to-header token
510
502
  ```
@@ -515,8 +507,9 @@ You can also configure CSRF protection on individual requests:
515
507
 
516
508
  ```typescript
517
509
  // Configure CSRF for a specific request
518
- const request = create.post()
519
- .withCsrfToken('request-specific-token') // Set a specific token
510
+ const request = create
511
+ .post()
512
+ .withCsrfToken("request-specific-token") // Set a specific token
520
513
  .withAntiCsrfHeaders() // Explicitly add X-Requested-With header
521
514
  .withoutCsrfProtection(); // Or disable all automatic CSRF protection
522
515
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-request",
3
- "version": "0.0.1-beta.13",
3
+ "version": "0.0.1-beta.14",
4
4
  "description": "A modern, chainable wrapper for fetch with automatic retries, timeouts, comprehensive error handling, and first-class TypeScript support",
5
5
  "main": "dist/library/index.js",
6
6
  "module": "dist/library/index.esm.js",