create-request 1.4.3-rc.1 → 1.4.3-rc.3

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 CHANGED
@@ -14,17 +14,19 @@
14
14
 
15
15
  - [Core Features](#core-features)
16
16
  - [Why create-request](#why-create-request)
17
+ - [Mental Model](#mental-model)
17
18
  - [Installation](#installation)
18
19
  - [Basic Usage](#basic-usage)
19
- - [API Builder](#api-builder)
20
- - [Automatic Retries with Delay](#automatic-retries-with-delay)
21
- - [Interceptors](#interceptors)
22
- - [Request Cancellation](#request-cancellation)
23
20
  - [URL Handling](#url-handling)
24
- - [Data Selection](#data-selection)
25
- - [GraphQL Support](#graphql-requests)
26
- - [TypeScript Support](#typescript-support)
27
- - [CSRF Protection](#csrf-protection)
21
+ - [Advanced Usage](#advanced-usage)
22
+ - [API Builder](#api-builder)
23
+ - [Automatic Retries with Delay](#automatic-retries-with-delay)
24
+ - [Interceptors](#interceptors)
25
+ - [Request Cancellation](#request-cancellation)
26
+ - [Data Selection](#data-selection)
27
+ - [TypeScript Support](#typescript-support)
28
+ - [CSRF Protection](#csrf-protection)
29
+ - [Subresource Integrity and Cache Control](#subresource-integrity-and-cache-control)
28
30
  - [Performance Considerations](#performance-considerations)
29
31
  - [Browser Support](#browser-support)
30
32
  - [Comparison of JavaScript HTTP Client Libraries](#comparison-of-javascript-http-client-libraries)
@@ -42,6 +44,7 @@
42
44
  - 🔁 **Automatic Retries** - Retry failed requests with customizable settings
43
45
  - 📉 **Reduced Boilerplate** - Write 60% less code for common API operations
44
46
  - 🔒 **CSRF Protection** - Built-in safeguards against cross-site request forgery
47
+ - 🏗️ **API Builder** - Create configured API instances with reusable default settings
45
48
  - 🛑 **Request Cancellation** - Abort requests on demand with AbortController integration
46
49
  - 🔌 **Interceptors** - Global and per-request interceptors for requests, responses, and errors
47
50
  - 🔷 **GraphQL Support** - Built-in GraphQL query and mutation helpers
@@ -94,6 +97,127 @@ function createUser(userData) {
94
97
  }
95
98
  ```
96
99
 
100
+ ## Mental Model
101
+
102
+ ### 1. **Separation of Building and Execution**
103
+
104
+ Requests are built first, then executed. This separation allows you to:
105
+
106
+ - Configure requests incrementally
107
+ - Reuse request configurations
108
+ - Pass requests around before executing them
109
+ - Chain configuration methods fluently
110
+
111
+ ```typescript
112
+ // Building phase: configure the request
113
+ const request = create
114
+ .get("https://api.example.com/users")
115
+ .withBearerToken(token)
116
+ .withTimeout(5000);
117
+
118
+ // Execution phase: actually make the HTTP call
119
+ const data = await request.getJson();
120
+ ```
121
+
122
+ ### 2. **Fluent Chainable Interface**
123
+
124
+ Every configuration method returns the request instance, enabling method chaining. This creates a readable, declarative API that reads like a sentence:
125
+
126
+ ```typescript
127
+ // Reads like: "Create a POST request to users endpoint, with auth, body, and timeout, then get JSON"
128
+ const user = await create
129
+ .post("https://api.example.com/users")
130
+ .withBearerToken(token)
131
+ .withBody(userData)
132
+ .withTimeout(3000)
133
+ .getJson();
134
+ ```
135
+
136
+ ### 3. **Configuration Layers**
137
+
138
+ Configuration follows a layered approach, with more specific settings overriding general ones:
139
+
140
+ 1. **Global Configuration** (via `create.config`) - Applies to all requests
141
+ 2. **API Builder Defaults** (via `create.api()`) - Applies to requests from that API instance
142
+ 3. **Per-Request Configuration** - Specific to individual requests
143
+
144
+ ```typescript
145
+ // Global: all requests get this
146
+ create.config.setCsrfToken("global-token");
147
+
148
+ // API instance: requests from this API get these defaults
149
+ const api = create
150
+ .api()
151
+ .withBaseURL("https://api.example.com")
152
+ .withBearerToken("default-token");
153
+
154
+ // Per-request: this specific request overrides the default token
155
+ const user = await api
156
+ .get("/users")
157
+ .withBearerToken("specific-token") // Overrides default-token
158
+ .getJson();
159
+ ```
160
+
161
+ ### 4. **Request Definition with `with...` Functions**
162
+
163
+ All request configuration is done through methods that start with `with...`. This consistent naming convention makes it immediately clear which methods are used for configuration:
164
+
165
+ ```typescript
166
+ // All configuration uses 'with...' prefix
167
+ const request = create
168
+ .get("https://api.example.com/users")
169
+ .withHeaders({ "X-API-Key": "abc123" })
170
+ .withBearerToken("token")
171
+ .withTimeout(5000)
172
+ .withRetries(3)
173
+ .withQueryParams({ page: 1 })
174
+ .withCookie("session", "abc123");
175
+ ```
176
+
177
+ This pattern makes the API self-documenting - any method starting with `with...` is a configuration method that returns the request instance for chaining.
178
+
179
+ ### 5. **Request Lifecycle**
180
+
181
+ The typical request lifecycle follows this pattern:
182
+
183
+ ```
184
+ Build → Configure → Execute → Transform → Handle
185
+ ```
186
+
187
+ 1. **Build**: Create a request with a method and URL (`create.get(url)`)
188
+ 2. **Configure**: Chain configuration methods using `with...` functions (`.withHeaders()`, `.withTimeout()`, etc.)
189
+ 3. **Execute**: Call an execution method (`.getJson()`, `.getData()`, etc.)
190
+ 4. **Transform**: Optionally transform the response (via `.getData()` selector or interceptors)
191
+ 5. **Handle**: Process the result or catch errors
192
+
193
+ ### 6. **Promise-Based Execution**
194
+
195
+ All execution methods return Promises, making the library compatible with:
196
+
197
+ - `async/await` syntax (recommended)
198
+ - `.then()/.catch()` chains
199
+ - Promise utilities like `Promise.all()`, `Promise.race()`, etc.
200
+
201
+ ```typescript
202
+ // All of these work:
203
+ const data1 = await request.getJson();
204
+
205
+ request.getJson().then(data => console.log(data));
206
+
207
+ const results = await Promise.all([
208
+ create.get("/users").getJson(),
209
+ create.get("/posts").getJson(),
210
+ ]);
211
+ ```
212
+
213
+ ### 7. **Comprehensive JSDoc Documentation**
214
+
215
+ The library includes extensive JSDoc documentation throughout the codebase. This documentation is valuable for developers of all levels:
216
+
217
+ - **For Junior Developers**: JSDoc provides clear explanations of what each method does, parameter types, return values, and usage examples directly in your IDE. This helps with learning and understanding the API without constantly referring to external documentation.
218
+
219
+ - **For Senior Developers**: JSDoc offers detailed type information, edge cases, and implementation details that enable deeper understanding and more advanced usage patterns. The type definitions help with TypeScript inference and ensure type safety.
220
+
97
221
  ## Installation
98
222
 
99
223
  ```bash
@@ -310,44 +434,6 @@ const merged = create
310
434
  .withQueryParams({ new: "param" }); // Both existing and new params included
311
435
  ```
312
436
 
313
- ### Subresource Integrity and Cache Control
314
-
315
- The library supports subresource integrity verification and cache control options:
316
-
317
- ```typescript
318
- // Subresource Integrity - ensures the fetched resource hasn't been tampered with
319
- const secureRequest = create
320
- .get("https://cdn.example.com/script.js")
321
- .withIntegrity("sha256-abcdef1234567890..."); // Browser will verify the hash
322
-
323
- // Cache Control - supports all cache modes via fluent API or string values
324
- const cachedRequest = create.get("https://api.example.com/data").withCache("no-cache"); // Direct string value
325
-
326
- // Using fluent API for cache modes
327
- const fluentCache = create.get("https://api.example.com/data").withCache.NO_CACHE(); // Fluent API method
328
-
329
- // All available cache modes:
330
- create
331
- .get("https://api.example.com/data")
332
- .withCache.DEFAULT() // Default cache behavior
333
- .withCache.NO_STORE() // Don't store in cache
334
- .withCache.RELOAD() // Reload from server
335
- .withCache.NO_CACHE() // Validate with server before using cache
336
- .withCache.FORCE_CACHE() // Use cache even if stale
337
- .withCache.ONLY_IF_CACHED(); // Only use cache, don't fetch from server
338
-
339
- // Using enum values (import from create-request)
340
- import { CacheMode } from "create-request";
341
-
342
- const enumCache = create.get("https://api.example.com/data").withCache(CacheMode.NO_CACHE);
343
-
344
- // Combining integrity and cache
345
- const secureCached = create
346
- .get("https://cdn.example.com/resource.js")
347
- .withIntegrity("sha256-abcdef1234567890...")
348
- .withCache("no-store"); // Ensure no caching for sensitive resources
349
- ```
350
-
351
437
  ### Executing Requests
352
438
 
353
439
  ```typescript
@@ -418,7 +504,34 @@ try {
418
504
  }
419
505
  ```
420
506
 
421
- ## API Builder
507
+ ## URL Handling
508
+
509
+ The library handles both absolute and relative URLs, and automatically merges query parameters:
510
+
511
+ ```typescript
512
+ // Relative URLs (preserved as-is)
513
+ const relative = await create.get("/api/users").getJson();
514
+
515
+ // Absolute URLs
516
+ const absolute = await create.get("https://api.example.com/users").getJson();
517
+
518
+ // Merging query params with existing URL params
519
+ const merged = await create
520
+ .get("https://api.example.com/users?page=1")
521
+ .withQueryParams({ limit: 20, sort: "name" })
522
+ .getJson();
523
+ // Result: https://api.example.com/users?page=1&limit=20&sort=name
524
+
525
+ // Special characters and unicode are properly encoded
526
+ const encoded = await create
527
+ .get("https://api.example.com/search")
528
+ .withQueryParams({ name: "用户名", filter: "status:active" })
529
+ .getJson();
530
+ ```
531
+
532
+ ## Advanced Usage
533
+
534
+ ### API Builder
422
535
 
423
536
  The API builder allows you to create configured API instances with default settings that can be reused across your application. This is perfect for setting up a base URL, default headers, timeout values, and other request configurations once and using them for all requests.
424
537
 
@@ -467,8 +580,6 @@ The API builder provides access to all request configuration methods from `BaseR
467
580
  - `withReferrer(referrer)` - Set default referrer
468
581
  - `withKeepAlive(keepalive)` - Configure keep-alive
469
582
  - `withIntegrity(integrity)` - Set integrity check
470
- - `withQueryParams(params)` - Add default query parameters
471
- - `withQueryParam(key, value)` - Add a single default query parameter
472
583
 
473
584
  **CSRF Protection:**
474
585
 
@@ -498,26 +609,6 @@ await api.get("/users").getJson();
498
609
  await api.post("/posts").withBody({ title: "Hello" }).getJson();
499
610
  ```
500
611
 
501
- #### Methods NOT Available on API Builder
502
-
503
- The following methods are **not available** on the API builder because they are request-specific and don't make sense as defaults:
504
-
505
- - **`withAbortController(controller)`** - AbortController is per-request, not a default
506
- - **`withBody(body)`** - Request bodies are different for each request
507
- - **`withGraphQL(query, variables, options)`** - GraphQL queries are request-specific
508
-
509
- These methods should be called directly on individual request instances:
510
-
511
- ```typescript
512
- const api = create.api().withBaseURL("https://api.example.com");
513
-
514
- // ✅ Good: Use withBody on individual requests
515
- await api.post("/users").withBody({ name: "John" }).getJson();
516
-
517
- // ❌ Bad: withBody is not available on the API builder
518
- // api.withBody({ name: "John" }); // This will be undefined
519
- ```
520
-
521
612
  #### URL Resolution
522
613
 
523
614
  The API builder intelligently resolves URLs:
@@ -622,7 +713,7 @@ async function deleteUser(id: string) {
622
713
  }
623
714
  ```
624
715
 
625
- ## Automatic Retries with Delay
716
+ ### Automatic Retries with Delay
626
717
 
627
718
  The `withRetries()` method supports both simple number-based retries and object-based configuration with customizable delays:
628
719
 
@@ -669,7 +760,7 @@ const request4 = create.get("https://api.example.com/data").withRetries({
669
760
  })
670
761
  ```
671
762
 
672
- ## Interceptors
763
+ ### Interceptors
673
764
 
674
765
  Interceptors allow you to modify requests, transform responses, or handle errors globally or per-request. This is perfect for adding authentication tokens, logging, error recovery, and more.
675
766
 
@@ -803,7 +894,7 @@ const asyncData = await create
803
894
  .getJson();
804
895
  ```
805
896
 
806
- ## Request Cancellation
897
+ ### Request Cancellation
807
898
 
808
899
  ```typescript
809
900
  const controller = new AbortController();
@@ -829,32 +920,7 @@ try {
829
920
  }
830
921
  ```
831
922
 
832
- ## URL Handling
833
-
834
- The library handles both absolute and relative URLs, and automatically merges query parameters:
835
-
836
- ```typescript
837
- // Relative URLs (preserved as-is)
838
- const relative = await create.get("/api/users").getJson();
839
-
840
- // Absolute URLs
841
- const absolute = await create.get("https://api.example.com/users").getJson();
842
-
843
- // Merging query params with existing URL params
844
- const merged = await create
845
- .get("https://api.example.com/users?page=1")
846
- .withQueryParams({ limit: 20, sort: "name" })
847
- .getJson();
848
- // Result: https://api.example.com/users?page=1&limit=20&sort=name
849
-
850
- // Special characters and unicode are properly encoded
851
- const encoded = await create
852
- .get("https://api.example.com/search")
853
- .withQueryParams({ name: "用户名", filter: "status:active" })
854
- .getJson();
855
- ```
856
-
857
- ## Data Selection
923
+ ### Data Selection
858
924
 
859
925
  The `getData` method provides a powerful way to extract and transform specific data from API responses:
860
926
 
@@ -896,7 +962,7 @@ try {
896
962
  }
897
963
  ```
898
964
 
899
- ## TypeScript Support
965
+ ### TypeScript Support
900
966
 
901
967
  ```typescript
902
968
  interface User {
@@ -942,7 +1008,7 @@ async function getUserById(id: number): Promise<User> {
942
1008
  }
943
1009
  ```
944
1010
 
945
- ## CSRF Protection
1011
+ ### CSRF Protection
946
1012
 
947
1013
  Cross-Site Request Forgery (CSRF) is a type of security vulnerability where unauthorized commands are executed on behalf of an authenticated user. `create-request` provides built-in protection mechanisms to help prevent CSRF attacks.
948
1014
 
@@ -986,6 +1052,44 @@ const request = create
986
1052
  .withoutCsrfProtection(); // Or disable all automatic CSRF protection
987
1053
  ```
988
1054
 
1055
+ ### Subresource Integrity and Cache Control
1056
+
1057
+ The library supports subresource integrity verification and cache control options:
1058
+
1059
+ ```typescript
1060
+ // Subresource Integrity - ensures the fetched resource hasn't been tampered with
1061
+ const secureRequest = create
1062
+ .get("https://cdn.example.com/script.js")
1063
+ .withIntegrity("sha256-abcdef1234567890..."); // Browser will verify the hash
1064
+
1065
+ // Cache Control - supports all cache modes via fluent API or string values
1066
+ const cachedRequest = create.get("https://api.example.com/data").withCache("no-cache"); // Direct string value
1067
+
1068
+ // Using fluent API for cache modes
1069
+ const fluentCache = create.get("https://api.example.com/data").withCache.NO_CACHE(); // Fluent API method
1070
+
1071
+ // All available cache modes:
1072
+ create
1073
+ .get("https://api.example.com/data")
1074
+ .withCache.DEFAULT() // Default cache behavior
1075
+ .withCache.NO_STORE() // Don't store in cache
1076
+ .withCache.RELOAD() // Reload from server
1077
+ .withCache.NO_CACHE() // Validate with server before using cache
1078
+ .withCache.FORCE_CACHE() // Use cache even if stale
1079
+ .withCache.ONLY_IF_CACHED(); // Only use cache, don't fetch from server
1080
+
1081
+ // Using enum values (import from create-request)
1082
+ import { CacheMode } from "create-request";
1083
+
1084
+ const enumCache = create.get("https://api.example.com/data").withCache(CacheMode.NO_CACHE);
1085
+
1086
+ // Combining integrity and cache
1087
+ const secureCached = create
1088
+ .get("https://cdn.example.com/resource.js")
1089
+ .withIntegrity("sha256-abcdef1234567890...")
1090
+ .withCache("no-store"); // Ensure no caching for sensitive resources
1091
+ ```
1092
+
989
1093
  ## Performance Considerations
990
1094
 
991
1095
  create-request is designed to be lightweight and efficient:
@@ -1008,26 +1112,27 @@ This library works with all browsers that support the Fetch API:
1008
1112
 
1009
1113
  ## Comparison of JavaScript HTTP Client Libraries
1010
1114
 
1011
- | Feature | create-request | Fetch | Axios | SuperAgent | Got | Ky | node-fetch | Redaxios |
1012
- | ------------------- | -------------- | ------ | ------- | ---------- | ------- | ------ | ---------- | -------- |
1013
- | **Size (min+gzip)** | ~5.8KB | Native | ~13.6KB | ~17.8KB | ~17.8KB | ~3.4KB | ~7.7KB | ~1KB |
1014
- | **Browser** | Modern | Modern | IE11+ | IE9+ | ❌ No | Modern | ❌ No | Modern |
1015
- | **Node.js** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
1016
- | **HTTP/2** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
1017
- | **Auto Retries** | ✅ | ❌ | 🛠️ | ✅ | ✅ | ✅ | ❌ | ❌ |
1018
- | **Cancellation** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
1019
- | **Auto JSON** | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
1020
- | **Timeout** | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
1021
- | **TypeScript** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
1022
- | **Streaming** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
1023
- | **Progress** | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
1024
- | **Cookies** | ✅ | ✅ | 🛠️ | ✅ | ✅ | ❌ | ❌ | ❌ |
1025
- | **Pagination API** | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
1026
- | **Zero Deps** | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ |
1027
- | **Chainable API** | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
1028
- | **CSRF Protection** | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
1029
- | **GraphQL Support** | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
1030
- | **Interceptors** | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
1115
+ | Feature | create-request | Fetch | Axios | SuperAgent | Got | Ky | node-fetch | Redaxios |
1116
+ | --------------------- | -------------- | ------ | ------- | ---------- | ------- | ------ | ---------- | -------- |
1117
+ | **Size (min+gzip)** | ~6.3KB | Native | ~13.6KB | ~17.8KB | ~17.8KB | ~3.4KB | ~7.7KB | ~1KB |
1118
+ | **Browser** | Modern | Modern | IE11+ | IE9+ | ❌ No | Modern | ❌ No | Modern |
1119
+ | **Node.js** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
1120
+ | **HTTP/2** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
1121
+ | **Auto Retries** | ✅ | ❌ | 🛠️ | ✅ | ✅ | ✅ | ❌ | ❌ |
1122
+ | **Cancellation** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
1123
+ | **Auto JSON** | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
1124
+ | **Timeout** | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
1125
+ | **TypeScript** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
1126
+ | **Streaming** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
1127
+ | **Progress** | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
1128
+ | **Cookies** | ✅ | ✅ | 🛠️ | ✅ | ✅ | ❌ | ❌ | ❌ |
1129
+ | **Pagination API** | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
1130
+ | **Zero Deps** | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ |
1131
+ | **Chainable API** | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
1132
+ | **CSRF Protection** | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
1133
+ | **GraphQL Support** | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
1134
+ | **Interceptors** | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
1135
+ | **Instance Creation** | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
1031
1136
 
1032
1137
  **Notes:**
1033
1138
 
@@ -1037,3 +1142,9 @@ This library works with all browsers that support the Fetch API:
1037
1142
  ## License
1038
1143
 
1039
1144
  MIT
1145
+
1146
+ ---
1147
+
1148
+ ## Website
1149
+
1150
+ Visit [create-request.com](https://create-request.com) for documentation, examples, and more resources.