create-request 0.0.1-beta.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Daniel Amenou
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,575 @@
1
+ # create-request
2
+
3
+ [![npm version](https://img.shields.io/npm/v/create-request.svg)](https://www.npmjs.com/package/create-request)
4
+ [![License](https://img.shields.io/npm/l/create-request.svg)](https://github.com/yourusername/create-request/blob/main/LICENSE)
5
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/create-request)](https://bundlephobia.com/package/create-request)
6
+
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
+
9
+ With first-class TypeScript support, built-in response parsing, and intuitive authentication helpers, `create-request` makes your API code more readable, more reliable, and fully type-safeβ€”all with zero dependencies and a tiny footprint.
10
+
11
+ ## Why create-request?
12
+
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, chainable API:
14
+
15
+ ```typescript
16
+ // Instead of verbose fetch code with manual JSON parsing, error handling, etc.
17
+ // You get a clean, intuitive API that just works
18
+ const users = await create.get()
19
+ .withTimeout(5000)
20
+ .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
38
+
39
+ - πŸ”„ **Fully Typed** - Complete TypeScript support with accurate type definitions
40
+ - πŸ”— **Chainable API** - Fluent interface for building requests
41
+ - ⏱️ **Timeout Support** - Set timeouts for any request (no more hanging requests!)
42
+ - πŸ” **Automatic Retries** - Smart retry mechanism with customizable strategies
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
51
+
52
+ ## Installation
53
+
54
+ ```bash
55
+ npm install create-request
56
+ ```
57
+
58
+ Or with yarn:
59
+
60
+ ```bash
61
+ yarn add create-request
62
+ ```
63
+
64
+ ## See the Difference: How create-request Transforms API Calls
65
+
66
+ ### 1. Simplified Error Handling
67
+
68
+ ```typescript
69
+ create.get()
70
+ .sendTo('https://api.example.com/data')
71
+ .json()
72
+ .then(data => {
73
+ // Process successful response
74
+ console.log(data);
75
+ })
76
+ .catch(error => {
77
+ if (error instanceof RequestError) {
78
+ // Rich error details that fetch doesn't provide:
79
+ console.log(`${error.status} error from ${error.method} ${error.url}`);
80
+ console.log(`Was it a timeout? ${error.timeoutError}`);
81
+
82
+ // Original error data still available:
83
+ console.log(error.response);
84
+ }
85
+ });
86
+ ```
87
+
88
+ ### 2. Type-Safe API Responses
89
+
90
+ ```typescript
91
+ interface User {
92
+ id: number;
93
+ name: string;
94
+ email: string;
95
+ }
96
+
97
+ // TypeScript knows exactly what you're getting back!
98
+ const users = await create.get()
99
+ .sendTo('https://api.example.com/users')
100
+ .json<User[]>();
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
111
+
112
+ const data = await create.get()
113
+ .withRetries(3)
114
+ .onRetry(({ retryCount, error }) => {
115
+ console.log(`Retry ${retryCount} after ${error.message}`);
116
+ })
117
+ .sendTo('https://api.example.com/flaky-endpoint')
118
+ .json();
119
+ ```
120
+
121
+ ## Basic Usage
122
+
123
+ ```typescript
124
+ import create from 'create-request';
125
+
126
+ // Simple GET request with chained response parsing
127
+ const users = await create.get()
128
+ .withTimeout(5000)
129
+ .sendTo('https://api.example.com/users')
130
+ .json(); // Parse response directly
131
+
132
+ // POST request with JSON body
133
+ const newUser = await create.post()
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()
157
+ ```
158
+
159
+ ### Request Configuration
160
+
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
+ ```typescript
215
+ // Add multiple query parameters
216
+ .withQueryParams({
217
+ search: 'keyword',
218
+ page: 1,
219
+ filters: ['active', 'verified']
220
+ })
221
+
222
+ // Add a single query parameter
223
+ .withQueryParam('sort', 'desc')
224
+
225
+ ```
226
+
227
+ #### Authentication
228
+
229
+ ```typescript
230
+ // Basic authentication
231
+ .withBasicAuth('username', 'password')
232
+
233
+ // Bearer token
234
+ .withBearerToken('your-jwt-token')
235
+
236
+ // Custom authorization header
237
+ .withAuthorization('Custom scheme-and-token')
238
+ ```
239
+
240
+ ### Requests with Body
241
+
242
+ For POST, PUT, and PATCH requests, you can set a body:
243
+
244
+ ```typescript
245
+ // JSON body (automatically sets Content-Type: application/json)
246
+ .withBody({ name: 'John', age: 30 })
247
+
248
+ // String body
249
+ .withBody('Plain text content')
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');
261
+
262
+ // ArrayBuffer body
263
+ const buffer = new ArrayBuffer(8);
264
+ const request = create.post()
265
+ .withBody(buffer)
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');
273
+
274
+ ```
275
+
276
+ ### Response Handling
277
+
278
+ The library provides convenient methods for handling responses that can be chained directly after `sendTo()`:
279
+
280
+ ```typescript
281
+ // Parse as JSON with type inference
282
+ const jsonData = await create.get()
283
+ .sendTo('https://api.example.com/data')
284
+ .json<MyDataType>();
285
+
286
+ // Get as text
287
+ const text = await create.get()
288
+ .sendTo('https://api.example.com/text')
289
+ .text();
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();
311
+ ```
312
+
313
+ ### Error Handling
314
+
315
+ The library provides a `RequestError` class with details about failed requests:
316
+
317
+ ```typescript
318
+ try {
319
+ const data = await create.get()
320
+ .sendTo('https://api.example.com/data')
321
+ .json();
322
+ } catch (error) {
323
+ if (error instanceof RequestError) {
324
+ console.log(error.message); // Error message
325
+ console.log(error.status); // HTTP status code (if available)
326
+ console.log(error.url); // Request URL
327
+ console.log(error.method); // HTTP method
328
+ console.log(error.timeoutError); // Whether it was a timeout
329
+ console.log(error.response); // Raw response (if available)
330
+ }
331
+ }
332
+ ```
333
+
334
+ ## Advanced Usage
335
+
336
+ ### Handling File Downloads
337
+
338
+ ```typescript
339
+ const blob = await create.get()
340
+ .withHeaders({ Accept: 'application/pdf' })
341
+ .sendTo('https://api.example.com/reports/123/download')
342
+ .blob();
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();
351
+
352
+ // Clean up
353
+ window.URL.revokeObjectURL(url);
354
+ ```
355
+
356
+ ### Working with AbortController
357
+
358
+ ```typescript
359
+ const controller = new AbortController();
360
+
361
+ // Pass the controller to the request
362
+ try {
363
+ const data = await create.get()
364
+ .withAbortController(controller)
365
+ .sendTo('https://api.example.com/data')
366
+ .json();
367
+ } catch (error) {
368
+ // Handle the aborted request
369
+ }
370
+
371
+ // Cancel the request after 2 seconds
372
+ setTimeout(() => controller.abort(), 2000);
373
+ ```
374
+
375
+ ### Request Priority
376
+
377
+ ```typescript
378
+ import { RequestPriority } from 'create-request';
379
+
380
+ // High priority for critical resources
381
+ const userProfile = await create.get()
382
+ .withPriority(RequestPriority.HIGH)
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();
391
+ ```
392
+
393
+ ### Creating Reusable Request Configurations
394
+
395
+ ```typescript
396
+ import { RequestPriority, CredentialsPolicy } from 'create-request';
397
+
398
+ function createAuthenticatedRequest(token) {
399
+ return create.get()
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);
408
+ }
409
+
410
+ // Later use the configured request
411
+ const users = await createAuthenticatedRequest(myToken)
412
+ .sendTo('https://api.example.com/users')
413
+ .json();
414
+ ```
415
+
416
+ ### Cookie Management
417
+
418
+ ```typescript
419
+ // Set multiple cookies in a single request
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');
428
+
429
+ // Combine with other header settings
430
+ const response = await create.get()
431
+ .withCookies({ sessionId: 'abc123' })
432
+ .withBearerToken('your-token-here')
433
+ .sendTo('https://api.example.com/protected-resource');
434
+ ```
435
+
436
+ ## Environment-Specific Limitations
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.
451
+
452
+ ### Server-Side (Node.js) Limitations
453
+
454
+ 1. **Missing Node.js Fetch** - Prior to Node 18, the Fetch API isn't available natively.
455
+
456
+ 2. **Self-signed Certificates** - Node.js rejects self-signed certificates by default. You may need additional configuration for development environments.
457
+
458
+ 3. **Memory Management** - When downloading large files or processing large responses, be mindful of memory consumption, especially when using `arrayBuffer()` or `blob()`.
459
+
460
+ 4. **Proxy Support** - Additional configuration may be needed to work with HTTP proxies in Node.js.
461
+
462
+ 5. **Limited Feature Support** - Features like `withKeepAlive` and `withPriority` might not be relevant or fully supported in Node.js environments.
463
+
464
+ ## Browser Compatibility
465
+
466
+ This library works with all browsers that support the Fetch API:
467
+
468
+ - Chrome 42+
469
+ - Firefox 39+
470
+ - Safari 10.1+
471
+ - Edge 14+
472
+ - Opera 29+
473
+
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
+ ## License
574
+
575
+ MIT