create-request 1.0.0 → 1.2.0
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 +23 -49
- package/dist/library/BaseRequest.d.ts +53 -3
- package/dist/library/BodyRequest.d.ts +14 -2
- package/dist/library/ResponseWrapper.d.ts +35 -5
- package/dist/library/enums.d.ts +11 -0
- package/dist/library/index.cjs +239 -98
- package/dist/library/index.cjs.map +1 -1
- package/dist/library/index.d.ts +1 -1
- package/dist/library/index.esm.js +239 -98
- package/dist/library/index.esm.js.map +1 -1
- package/dist/library/index.esm.min.js +1 -1
- package/dist/library/index.esm.min.js.map +1 -1
- package/dist/library/index.min.cjs +1 -1
- package/dist/library/index.min.cjs.map +1 -1
- package/dist/library/types.d.ts +10 -3
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
- [Installation](#installation)
|
|
15
15
|
- [Basic Usage](#basic-usage)
|
|
16
16
|
- [Advanced Usage](#advanced-usage)
|
|
17
|
-
- [GraphQL Support](#graphql-
|
|
17
|
+
- [GraphQL Support](#graphql-requests)
|
|
18
18
|
- [Interceptors](#interceptors)
|
|
19
19
|
- [TypeScript Support](#typescript-support)
|
|
20
20
|
- [CSRF Protection](#csrf-protection)
|
|
@@ -247,13 +247,33 @@ const result = await create
|
|
|
247
247
|
.getJson();
|
|
248
248
|
```
|
|
249
249
|
|
|
250
|
+
#### GraphQL Error Handling
|
|
251
|
+
|
|
252
|
+
GraphQL errors do not cause exceptions by default. Use the `throwOnError` option to make them throw exceptions:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
// Throw an error if the GraphQL response contains errors
|
|
256
|
+
try {
|
|
257
|
+
const user = await create
|
|
258
|
+
.post("https://api.example.com/graphql")
|
|
259
|
+
.withGraphQL(
|
|
260
|
+
"query GetUser($id: ID!) { user(id: $id) { name email } }",
|
|
261
|
+
{ id: "123" },
|
|
262
|
+
{ throwOnError: true }
|
|
263
|
+
)
|
|
264
|
+
.getJson();
|
|
265
|
+
} catch (error) {
|
|
266
|
+
console.error(error.message);
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
250
270
|
The `withGraphQL` method automatically:
|
|
251
271
|
|
|
252
272
|
- Formats the body as JSON with `query` and optional `variables` properties
|
|
253
273
|
- Sets `Content-Type` to `application/json`
|
|
254
|
-
- Trims whitespace from the query string
|
|
255
274
|
- Validates the query is non-empty
|
|
256
275
|
- Validates variables are a plain object (not arrays or null)
|
|
276
|
+
- Optionally throws errors when GraphQL response contains errors (with `throwOnError: true`)
|
|
257
277
|
|
|
258
278
|
### Query Parameters Advanced Features
|
|
259
279
|
|
|
@@ -358,52 +378,6 @@ try {
|
|
|
358
378
|
|
|
359
379
|
## Advanced Usage
|
|
360
380
|
|
|
361
|
-
### GraphQL Support
|
|
362
|
-
|
|
363
|
-
`create-request` provides first-class support for GraphQL with the `withGraphQL` method:
|
|
364
|
-
|
|
365
|
-
```typescript
|
|
366
|
-
// Simple query
|
|
367
|
-
const query = "query { user { name email } }";
|
|
368
|
-
const data = await create
|
|
369
|
-
.post("https://api.example.com/graphql")
|
|
370
|
-
.withGraphQL(query)
|
|
371
|
-
.getJson();
|
|
372
|
-
|
|
373
|
-
// Query with variables
|
|
374
|
-
const queryWithVars = "query GetUser($id: ID!) { user(id: $id) { name email } }";
|
|
375
|
-
const user = await create
|
|
376
|
-
.post("https://api.example.com/graphql")
|
|
377
|
-
.withGraphQL(queryWithVars, { id: "123" })
|
|
378
|
-
.getJson();
|
|
379
|
-
|
|
380
|
-
// Mutation
|
|
381
|
-
const mutation =
|
|
382
|
-
"mutation CreateUser($name: String!) { createUser(name: $name) { id name } }";
|
|
383
|
-
const result = await create
|
|
384
|
-
.post("https://api.example.com/graphql")
|
|
385
|
-
.withGraphQL(mutation, { name: "John Doe" })
|
|
386
|
-
.getJson();
|
|
387
|
-
|
|
388
|
-
// Complex variables with nested objects
|
|
389
|
-
const complexQuery =
|
|
390
|
-
"query SearchUsers($filters: UserFilters!) { users(filters: $filters) { id name } }";
|
|
391
|
-
const results = await create
|
|
392
|
-
.post("https://api.example.com/graphql")
|
|
393
|
-
.withGraphQL(complexQuery, {
|
|
394
|
-
filters: {
|
|
395
|
-
name: "John",
|
|
396
|
-
age: 30,
|
|
397
|
-
tags: ["active", "verified"],
|
|
398
|
-
metadata: {
|
|
399
|
-
source: "web",
|
|
400
|
-
verified: true,
|
|
401
|
-
},
|
|
402
|
-
},
|
|
403
|
-
})
|
|
404
|
-
.getJson();
|
|
405
|
-
```
|
|
406
|
-
|
|
407
381
|
### Interceptors
|
|
408
382
|
|
|
409
383
|
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.
|
|
@@ -745,7 +719,7 @@ This library works with all browsers that support the Fetch API:
|
|
|
745
719
|
|
|
746
720
|
| Feature | create-request | Fetch | Axios | SuperAgent | Got | Ky | node-fetch | Redaxios |
|
|
747
721
|
| ------------------- | -------------- | ------ | ------- | ---------- | ------- | ------ | ---------- | -------- |
|
|
748
|
-
| **Size (min+gzip)** | ~5.
|
|
722
|
+
| **Size (min+gzip)** | ~5.8KB | Native | ~13.6KB | ~17.8KB | ~17.8KB | ~3.4KB | ~7.7KB | ~1KB |
|
|
749
723
|
| **Browser** | Modern | Modern | IE11+ | IE9+ | ❌ No | Modern | ❌ No | Modern |
|
|
750
724
|
| **Node.js** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
751
725
|
| **HTTP/2** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type HttpMethod, RedirectMode, RequestMode, RequestPriority, ReferrerPolicy, CredentialsPolicy } from "./enums.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { RetryCallback, CookiesRecord, CookieOptions, RequestOptions, GraphQLOptions, ErrorInterceptor, RequestInterceptor, ResponseInterceptor } from "./types.js";
|
|
3
3
|
import { ResponseWrapper } from "./ResponseWrapper.js";
|
|
4
4
|
/**
|
|
5
5
|
* Base class with common functionality for all request types
|
|
@@ -16,6 +16,11 @@ export declare abstract class BaseRequest {
|
|
|
16
16
|
private responseInterceptors;
|
|
17
17
|
private errorInterceptors;
|
|
18
18
|
constructor(url: string);
|
|
19
|
+
/**
|
|
20
|
+
* Get GraphQL options if set (only for BodyRequest subclasses)
|
|
21
|
+
* @returns GraphQL options or undefined
|
|
22
|
+
*/
|
|
23
|
+
protected getGraphQLOptions(): GraphQLOptions | undefined;
|
|
19
24
|
/**
|
|
20
25
|
* Creates a fluent API for setting enum-based options
|
|
21
26
|
* Combines direct setter with convenience methods
|
|
@@ -52,7 +57,7 @@ export declare abstract class BaseRequest {
|
|
|
52
57
|
*
|
|
53
58
|
* @param timeout - The timeout in milliseconds
|
|
54
59
|
* @returns The request instance for chaining
|
|
55
|
-
* @throws
|
|
60
|
+
* @throws RequestError if timeout is not a positive number
|
|
56
61
|
*
|
|
57
62
|
* @example
|
|
58
63
|
* request.withTimeout(5000); // 5 seconds timeout
|
|
@@ -63,7 +68,7 @@ export declare abstract class BaseRequest {
|
|
|
63
68
|
*
|
|
64
69
|
* @param retries - Number of retry attempts before failing
|
|
65
70
|
* @returns The request instance for chaining
|
|
66
|
-
* @throws
|
|
71
|
+
* @throws RequestError if retries is not a non-negative integer
|
|
67
72
|
*
|
|
68
73
|
* @example
|
|
69
74
|
* request.withRetries(3); // Retry up to 3 times
|
|
@@ -154,6 +159,29 @@ export declare abstract class BaseRequest {
|
|
|
154
159
|
LOW: () => BaseRequest;
|
|
155
160
|
AUTO: () => BaseRequest;
|
|
156
161
|
};
|
|
162
|
+
/**
|
|
163
|
+
* Sets the integrity hash for subresource integrity verification
|
|
164
|
+
* @param integrity - The integrity hash string (e.g., "sha256-...")
|
|
165
|
+
* @returns The instance for chaining
|
|
166
|
+
* @example
|
|
167
|
+
* request.withIntegrity("sha256-abcdef1234567890...")
|
|
168
|
+
*/
|
|
169
|
+
withIntegrity(integrity: string): this;
|
|
170
|
+
/**
|
|
171
|
+
* Sets cache mode - supports both direct call and fluent API
|
|
172
|
+
* @example
|
|
173
|
+
* request.withCache("no-cache")
|
|
174
|
+
* request.withCache(CacheMode.NO_CACHE)
|
|
175
|
+
* request.withCache.NO_CACHE()
|
|
176
|
+
*/
|
|
177
|
+
get withCache(): ((cache: string) => BaseRequest) & {
|
|
178
|
+
DEFAULT: () => BaseRequest;
|
|
179
|
+
NO_STORE: () => BaseRequest;
|
|
180
|
+
RELOAD: () => BaseRequest;
|
|
181
|
+
NO_CACHE: () => BaseRequest;
|
|
182
|
+
FORCE_CACHE: () => BaseRequest;
|
|
183
|
+
ONLY_IF_CACHED: () => BaseRequest;
|
|
184
|
+
};
|
|
157
185
|
/**
|
|
158
186
|
* Adds query parameters to the request URL
|
|
159
187
|
* @param params - An object containing the query parameters
|
|
@@ -309,9 +337,20 @@ export declare abstract class BaseRequest {
|
|
|
309
337
|
* Execute the request and parse the response as JSON
|
|
310
338
|
*
|
|
311
339
|
* @returns A promise that resolves to the parsed JSON data
|
|
340
|
+
* @throws {RequestError} When the request fails, JSON parsing fails, GraphQL errors occur (if throwOnError enabled), or body is already consumed
|
|
312
341
|
*
|
|
313
342
|
* @example
|
|
314
343
|
* const users = await request.getJson<User[]>();
|
|
344
|
+
*
|
|
345
|
+
* @example
|
|
346
|
+
* // Error handling - errors are always RequestError
|
|
347
|
+
* try {
|
|
348
|
+
* const data = await request.getJson();
|
|
349
|
+
* } catch (error) {
|
|
350
|
+
* if (error instanceof RequestError) {
|
|
351
|
+
* console.log(error.status, error.url, error.method);
|
|
352
|
+
* }
|
|
353
|
+
* }
|
|
315
354
|
*/
|
|
316
355
|
getJson<T = unknown>(): Promise<T>;
|
|
317
356
|
/**
|
|
@@ -347,6 +386,7 @@ export declare abstract class BaseRequest {
|
|
|
347
386
|
*
|
|
348
387
|
* @param selector - Optional function to extract and transform data
|
|
349
388
|
* @returns A promise that resolves to the selected data
|
|
389
|
+
* @throws {RequestError} When the request fails, JSON parsing fails, or the selector throws an error
|
|
350
390
|
*
|
|
351
391
|
* @example
|
|
352
392
|
* // Get full response
|
|
@@ -354,6 +394,16 @@ export declare abstract class BaseRequest {
|
|
|
354
394
|
*
|
|
355
395
|
* // Extract specific data
|
|
356
396
|
* const users = await request.getData(data => data.results.users);
|
|
397
|
+
*
|
|
398
|
+
* @example
|
|
399
|
+
* // Error handling - errors are always RequestError
|
|
400
|
+
* try {
|
|
401
|
+
* const data = await request.getData();
|
|
402
|
+
* } catch (error) {
|
|
403
|
+
* if (error instanceof RequestError) {
|
|
404
|
+
* console.log(error.status, error.url, error.method);
|
|
405
|
+
* }
|
|
406
|
+
* }
|
|
357
407
|
*/
|
|
358
408
|
getData<T = unknown, R = T>(selector?: (data: T) => R): Promise<T | R>;
|
|
359
409
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BaseRequest } from "./BaseRequest.js";
|
|
2
|
-
import type { Body } from "./types.js";
|
|
2
|
+
import type { Body, GraphQLOptions } from "./types.js";
|
|
3
3
|
import type { ResponseWrapper } from "./ResponseWrapper.js";
|
|
4
4
|
/**
|
|
5
5
|
* Base class for requests that can have a body (POST, PUT, PATCH)
|
|
@@ -7,6 +7,7 @@ import type { ResponseWrapper } from "./ResponseWrapper.js";
|
|
|
7
7
|
export declare abstract class BodyRequest extends BaseRequest {
|
|
8
8
|
protected body?: Body;
|
|
9
9
|
private bodyType?;
|
|
10
|
+
private graphQLOptions;
|
|
10
11
|
constructor(url: string);
|
|
11
12
|
/**
|
|
12
13
|
* Sets the body of the request
|
|
@@ -19,6 +20,7 @@ export declare abstract class BodyRequest extends BaseRequest {
|
|
|
19
20
|
*
|
|
20
21
|
* @param query - The GraphQL query or mutation string
|
|
21
22
|
* @param variables - Optional variables object to pass with the query
|
|
23
|
+
* @param options - Optional GraphQL-specific options
|
|
22
24
|
* @returns The request instance for chaining
|
|
23
25
|
*
|
|
24
26
|
* @example
|
|
@@ -28,13 +30,23 @@ export declare abstract class BodyRequest extends BaseRequest {
|
|
|
28
30
|
* @example
|
|
29
31
|
* const request = new PostRequest('/graphql')
|
|
30
32
|
* .withGraphQL('mutation { createUser(name: $name) { id } }', { name: 'John' });
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* // Throw an error if the GraphQL response contains errors
|
|
36
|
+
* const request = new PostRequest('/graphql')
|
|
37
|
+
* .withGraphQL('query { user { id } }', undefined, { throwOnError: true });
|
|
31
38
|
*/
|
|
32
|
-
withGraphQL(query: string, variables?: Record<string, unknown
|
|
39
|
+
withGraphQL(query: string, variables?: Record<string, unknown>, options?: GraphQLOptions): this;
|
|
33
40
|
/**
|
|
34
41
|
* Check if Content-Type header is already set (case-insensitive)
|
|
35
42
|
*/
|
|
36
43
|
private hasContentType;
|
|
37
44
|
private setContentTypeIfNeeded;
|
|
45
|
+
/**
|
|
46
|
+
* Get the GraphQL options if set
|
|
47
|
+
* @returns The GraphQL options or undefined
|
|
48
|
+
*/
|
|
49
|
+
protected getGraphQLOptions(): GraphQLOptions | undefined;
|
|
38
50
|
/**
|
|
39
51
|
* Execute the request and return the ResponseWrapper
|
|
40
52
|
* Overrides the base implementation to add body handling
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { GraphQLOptions } from "./types.js";
|
|
1
2
|
/**
|
|
2
3
|
* Wrapper for HTTP responses with methods to transform the response data
|
|
3
4
|
* Provides caching and conversion between different response formats.
|
|
@@ -10,22 +11,40 @@ export declare class ResponseWrapper {
|
|
|
10
11
|
private jsonCache;
|
|
11
12
|
private blobCache;
|
|
12
13
|
private bodyUsed;
|
|
13
|
-
|
|
14
|
+
private graphQLOptions?;
|
|
15
|
+
constructor(response: Response, url?: string, method?: string, graphQLOptions?: GraphQLOptions);
|
|
14
16
|
get status(): number;
|
|
15
17
|
get statusText(): string;
|
|
16
18
|
get headers(): Headers;
|
|
17
19
|
get ok(): boolean;
|
|
18
20
|
get raw(): Response;
|
|
21
|
+
/**
|
|
22
|
+
* Check for GraphQL errors and throw if throwOnError is enabled
|
|
23
|
+
* @param data - The parsed JSON data
|
|
24
|
+
* @throws RequestError if GraphQL response contains errors and throwOnError is enabled
|
|
25
|
+
*/
|
|
26
|
+
private checkGraphQLErrors;
|
|
19
27
|
/**
|
|
20
28
|
* Parse the response body as JSON
|
|
21
29
|
* Caches the result for subsequent calls.
|
|
30
|
+
* If GraphQL options are set with throwOnError=true, will check for GraphQL errors and throw.
|
|
22
31
|
*
|
|
23
32
|
* @returns The parsed JSON data
|
|
24
|
-
* @throws
|
|
33
|
+
* @throws {RequestError} When the request fails, JSON parsing fails, GraphQL errors occur (if throwOnError enabled), or body is already consumed
|
|
25
34
|
*
|
|
26
35
|
* @example
|
|
27
36
|
* const data = await response.getJson();
|
|
28
37
|
* console.log(data.items);
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* // Error handling - errors are always RequestError
|
|
41
|
+
* try {
|
|
42
|
+
* const data = await response.getJson();
|
|
43
|
+
* } catch (error) {
|
|
44
|
+
* if (error instanceof RequestError) {
|
|
45
|
+
* console.log(error.status, error.url, error.method);
|
|
46
|
+
* }
|
|
47
|
+
* }
|
|
29
48
|
*/
|
|
30
49
|
getJson<T = unknown>(): Promise<T>;
|
|
31
50
|
/**
|
|
@@ -34,7 +53,7 @@ export declare class ResponseWrapper {
|
|
|
34
53
|
* if the body has already been consumed in those formats.
|
|
35
54
|
*
|
|
36
55
|
* @returns The response text
|
|
37
|
-
* @throws
|
|
56
|
+
* @throws {RequestError} When reading fails or the response has already been consumed in an incompatible format
|
|
38
57
|
*
|
|
39
58
|
* @example
|
|
40
59
|
* const text = await response.getText();
|
|
@@ -46,7 +65,7 @@ export declare class ResponseWrapper {
|
|
|
46
65
|
* if the body has already been consumed as text.
|
|
47
66
|
*
|
|
48
67
|
* @returns The response as a Blob
|
|
49
|
-
* @throws
|
|
68
|
+
* @throws {RequestError} When reading fails or the response has already been consumed in an incompatible format
|
|
50
69
|
*
|
|
51
70
|
* @example
|
|
52
71
|
* const blob = await response.getBlob();
|
|
@@ -58,7 +77,7 @@ export declare class ResponseWrapper {
|
|
|
58
77
|
* This method consumes the body and should only be called once.
|
|
59
78
|
*
|
|
60
79
|
* @returns The response body as a ReadableStream or null
|
|
61
|
-
* @throws
|
|
80
|
+
* @throws {RequestError} When the response body has already been consumed
|
|
62
81
|
*
|
|
63
82
|
* @example
|
|
64
83
|
* const stream = response.getBody();
|
|
@@ -74,6 +93,7 @@ export declare class ResponseWrapper {
|
|
|
74
93
|
*
|
|
75
94
|
* @param selector - Optional function to extract and transform data
|
|
76
95
|
* @returns A promise that resolves to the selected data
|
|
96
|
+
* @throws {RequestError} When the request fails, JSON parsing fails, or the selector throws an error
|
|
77
97
|
*
|
|
78
98
|
* @example
|
|
79
99
|
* // Get full response
|
|
@@ -81,6 +101,16 @@ export declare class ResponseWrapper {
|
|
|
81
101
|
*
|
|
82
102
|
* // Extract specific data
|
|
83
103
|
* const users = await response.getData(data => data.results.users);
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* // Error handling - errors are always RequestError
|
|
107
|
+
* try {
|
|
108
|
+
* const data = await response.getData();
|
|
109
|
+
* } catch (error) {
|
|
110
|
+
* if (error instanceof RequestError) {
|
|
111
|
+
* console.log(error.status, error.url, error.method);
|
|
112
|
+
* }
|
|
113
|
+
* }
|
|
84
114
|
*/
|
|
85
115
|
getData<T = unknown, R = T>(selector?: (data: T) => R): Promise<T | R>;
|
|
86
116
|
}
|
package/dist/library/enums.d.ts
CHANGED
|
@@ -72,3 +72,14 @@ export declare enum ReferrerPolicy {
|
|
|
72
72
|
NO_REFERRER_WHEN_DOWNGRADE = "no-referrer-when-downgrade",
|
|
73
73
|
STRICT_ORIGIN_WHEN_CROSS_ORIGIN = "strict-origin-when-cross-origin"
|
|
74
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Cache modes for fetch requests
|
|
77
|
+
*/
|
|
78
|
+
export declare enum CacheMode {
|
|
79
|
+
RELOAD = "reload",
|
|
80
|
+
DEFAULT = "default",
|
|
81
|
+
NO_CACHE = "no-cache",
|
|
82
|
+
NO_STORE = "no-store",
|
|
83
|
+
FORCE_CACHE = "force-cache",
|
|
84
|
+
ONLY_IF_CACHED = "only-if-cached"
|
|
85
|
+
}
|