@zimic/fetch 0.1.0-canary.9 → 0.1.1-canary.1
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.md +1 -1
- package/README.md +136 -175
- package/dist/index.d.ts +871 -44
- package/dist/index.js +77 -42
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +78 -43
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -12
- package/src/client/FetchClient.ts +113 -66
- package/src/client/errors/FetchResponseError.ts +47 -6
- package/src/client/factory.ts +56 -5
- package/src/client/types/json.ts +7 -0
- package/src/client/types/public.ts +587 -51
- package/src/client/types/requests.ts +257 -49
- package/src/index.ts +5 -9
- package/src/types/requests.ts +1 -2
- package/src/utils/environment.ts +3 -0
- package/src/utils/files.ts +4 -19
- package/src/types/strings.d.ts +0 -9
- package/src/types/utils.ts +0 -11
- package/src/utils/imports.ts +0 -14
- package/src/utils/urls.ts +0 -43
|
@@ -4,35 +4,54 @@ import {
|
|
|
4
4
|
HttpSearchParams,
|
|
5
5
|
LiteralHttpSchemaPathFromNonLiteral,
|
|
6
6
|
HttpSchema,
|
|
7
|
+
HttpHeaders,
|
|
7
8
|
} from '@zimic/http';
|
|
8
|
-
|
|
9
|
-
import
|
|
10
|
-
import
|
|
9
|
+
import createRegexFromURL from '@zimic/utils/url/createRegExpFromURL';
|
|
10
|
+
import excludeURLParams from '@zimic/utils/url/excludeURLParams';
|
|
11
|
+
import joinURL from '@zimic/utils/url/joinURL';
|
|
11
12
|
|
|
12
13
|
import FetchResponseError from './errors/FetchResponseError';
|
|
13
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
FetchInput,
|
|
16
|
+
FetchOptions,
|
|
17
|
+
Fetch,
|
|
18
|
+
FetchClient as PublicFetchClient,
|
|
19
|
+
FetchDefaults,
|
|
20
|
+
FetchFunction,
|
|
21
|
+
} from './types/public';
|
|
14
22
|
import { FetchRequestConstructor, FetchRequestInit, FetchRequest, FetchResponse } from './types/requests';
|
|
15
23
|
|
|
16
|
-
class FetchClient<Schema extends HttpSchema>
|
|
24
|
+
class FetchClient<Schema extends HttpSchema>
|
|
25
|
+
implements Omit<PublicFetchClient<Schema>, 'defaults' | 'loose' | 'Request'>
|
|
26
|
+
{
|
|
17
27
|
fetch: Fetch<Schema>;
|
|
18
28
|
|
|
19
29
|
constructor({ onRequest, onResponse, ...defaults }: FetchOptions<Schema>) {
|
|
20
30
|
this.fetch = this.createFetchFunction();
|
|
21
|
-
|
|
22
|
-
this.fetch.
|
|
31
|
+
|
|
32
|
+
this.fetch.defaults = {
|
|
33
|
+
...defaults,
|
|
34
|
+
headers: defaults.headers ?? {},
|
|
35
|
+
searchParams: defaults.searchParams ?? {},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
|
+
this.fetch.loose = this.fetch as Fetch<any> as FetchFunction.Loose;
|
|
40
|
+
|
|
41
|
+
this.fetch.Request = this.createRequestClass(this.fetch.defaults);
|
|
23
42
|
this.fetch.onRequest = onRequest;
|
|
24
43
|
this.fetch.onResponse = onResponse;
|
|
25
44
|
}
|
|
26
45
|
|
|
27
46
|
private createFetchFunction() {
|
|
28
47
|
const fetch = async <
|
|
29
|
-
Path extends HttpSchemaPath.NonLiteral<Schema, Method>,
|
|
30
48
|
Method extends HttpSchemaMethod<Schema>,
|
|
49
|
+
Path extends HttpSchemaPath.NonLiteral<Schema, Method>,
|
|
31
50
|
>(
|
|
32
|
-
input: FetchInput<Schema,
|
|
33
|
-
init: FetchRequestInit<Schema, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path
|
|
51
|
+
input: FetchInput<Schema, Method, Path>,
|
|
52
|
+
init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>,
|
|
34
53
|
) => {
|
|
35
|
-
const request = await this.createFetchRequest<
|
|
54
|
+
const request = await this.createFetchRequest<Method, Path>(input, init);
|
|
36
55
|
const requestClone = request.clone();
|
|
37
56
|
|
|
38
57
|
const rawResponse = await globalThis.fetch(
|
|
@@ -40,8 +59,8 @@ class FetchClient<Schema extends HttpSchema> {
|
|
|
40
59
|
requestClone as Request,
|
|
41
60
|
);
|
|
42
61
|
const response = await this.createFetchResponse<
|
|
43
|
-
|
|
44
|
-
Method
|
|
62
|
+
Method,
|
|
63
|
+
LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>
|
|
45
64
|
>(request, rawResponse);
|
|
46
65
|
|
|
47
66
|
return response;
|
|
@@ -53,11 +72,11 @@ class FetchClient<Schema extends HttpSchema> {
|
|
|
53
72
|
}
|
|
54
73
|
|
|
55
74
|
private async createFetchRequest<
|
|
56
|
-
Path extends HttpSchemaPath.NonLiteral<Schema, Method>,
|
|
57
75
|
Method extends HttpSchemaMethod<Schema>,
|
|
76
|
+
Path extends HttpSchemaPath.NonLiteral<Schema, Method>,
|
|
58
77
|
>(
|
|
59
|
-
input: FetchInput<Schema,
|
|
60
|
-
init: FetchRequestInit<Schema, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path
|
|
78
|
+
input: FetchInput<Schema, Method, Path>,
|
|
79
|
+
init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>,
|
|
61
80
|
) {
|
|
62
81
|
let request = input instanceof Request ? input : new this.fetch.Request(input, init);
|
|
63
82
|
|
|
@@ -65,7 +84,6 @@ class FetchClient<Schema extends HttpSchema> {
|
|
|
65
84
|
const requestAfterInterceptor = await this.fetch.onRequest(
|
|
66
85
|
// Optimize type checking by narrowing the type of request
|
|
67
86
|
request as FetchRequest.Loose,
|
|
68
|
-
this.fetch,
|
|
69
87
|
);
|
|
70
88
|
|
|
71
89
|
if (requestAfterInterceptor !== request) {
|
|
@@ -73,7 +91,7 @@ class FetchClient<Schema extends HttpSchema> {
|
|
|
73
91
|
|
|
74
92
|
request = isFetchRequest
|
|
75
93
|
? (requestAfterInterceptor as Request as typeof request)
|
|
76
|
-
: new this.fetch.Request(requestAfterInterceptor as FetchInput<Schema,
|
|
94
|
+
: new this.fetch.Request(requestAfterInterceptor as FetchInput<Schema, Method, Path>, init);
|
|
77
95
|
}
|
|
78
96
|
}
|
|
79
97
|
|
|
@@ -81,16 +99,15 @@ class FetchClient<Schema extends HttpSchema> {
|
|
|
81
99
|
}
|
|
82
100
|
|
|
83
101
|
private async createFetchResponse<
|
|
84
|
-
Path extends HttpSchemaPath<Schema, Method>,
|
|
85
102
|
Method extends HttpSchemaMethod<Schema>,
|
|
86
|
-
|
|
87
|
-
|
|
103
|
+
Path extends HttpSchemaPath.Literal<Schema, Method>,
|
|
104
|
+
>(fetchRequest: FetchRequest<Schema, Method, Path>, rawResponse: Response) {
|
|
105
|
+
let response = this.defineFetchResponseProperties<Method, Path>(fetchRequest, rawResponse);
|
|
88
106
|
|
|
89
107
|
if (this.fetch.onResponse) {
|
|
90
108
|
const responseAfterInterceptor = await this.fetch.onResponse(
|
|
91
109
|
// Optimize type checking by narrowing the type of response
|
|
92
110
|
response as FetchResponse.Loose,
|
|
93
|
-
this.fetch,
|
|
94
111
|
);
|
|
95
112
|
|
|
96
113
|
const isFetchResponse =
|
|
@@ -100,17 +117,17 @@ class FetchClient<Schema extends HttpSchema> {
|
|
|
100
117
|
|
|
101
118
|
response = isFetchResponse
|
|
102
119
|
? (responseAfterInterceptor as typeof response)
|
|
103
|
-
: this.defineFetchResponseProperties<
|
|
120
|
+
: this.defineFetchResponseProperties<Method, Path>(fetchRequest, responseAfterInterceptor);
|
|
104
121
|
}
|
|
105
122
|
|
|
106
123
|
return response;
|
|
107
124
|
}
|
|
108
125
|
|
|
109
126
|
private defineFetchResponseProperties<
|
|
110
|
-
Path extends HttpSchemaPath<Schema, Method>,
|
|
111
127
|
Method extends HttpSchemaMethod<Schema>,
|
|
112
|
-
|
|
113
|
-
|
|
128
|
+
Path extends HttpSchemaPath.Literal<Schema, Method>,
|
|
129
|
+
>(fetchRequest: FetchRequest<Schema, Method, Path>, response: Response) {
|
|
130
|
+
const fetchResponse = response as FetchResponse<Schema, Method, Path>;
|
|
114
131
|
|
|
115
132
|
Object.defineProperty(fetchResponse, 'request', {
|
|
116
133
|
value: fetchRequest satisfies FetchResponse.Loose['request'],
|
|
@@ -119,13 +136,20 @@ class FetchClient<Schema extends HttpSchema> {
|
|
|
119
136
|
configurable: false,
|
|
120
137
|
});
|
|
121
138
|
|
|
122
|
-
|
|
123
|
-
fetchResponse.ok ? null : new FetchResponseError(fetchRequest, fetchResponse)
|
|
124
|
-
) satisfies FetchResponse.Loose['error'];
|
|
139
|
+
let responseError: FetchResponse.Loose['error'] | undefined;
|
|
125
140
|
|
|
126
141
|
Object.defineProperty(fetchResponse, 'error', {
|
|
127
|
-
|
|
128
|
-
|
|
142
|
+
get() {
|
|
143
|
+
if (responseError === undefined) {
|
|
144
|
+
responseError = fetchResponse.ok
|
|
145
|
+
? null
|
|
146
|
+
: new FetchResponseError(
|
|
147
|
+
fetchRequest,
|
|
148
|
+
fetchResponse as FetchResponse<Schema, Method, Path, true, 'manual'>,
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
return responseError;
|
|
152
|
+
},
|
|
129
153
|
enumerable: true,
|
|
130
154
|
configurable: false,
|
|
131
155
|
});
|
|
@@ -133,53 +157,76 @@ class FetchClient<Schema extends HttpSchema> {
|
|
|
133
157
|
return fetchResponse;
|
|
134
158
|
}
|
|
135
159
|
|
|
136
|
-
private createRequestClass(defaults:
|
|
160
|
+
private createRequestClass(defaults: FetchDefaults) {
|
|
137
161
|
class Request<
|
|
138
|
-
Path extends HttpSchemaPath.NonLiteral<Schema, Method>,
|
|
139
162
|
Method extends HttpSchemaMethod<Schema>,
|
|
163
|
+
Path extends HttpSchemaPath.NonLiteral<Schema, Method>,
|
|
140
164
|
> extends globalThis.Request {
|
|
141
165
|
path: LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>;
|
|
142
166
|
|
|
143
167
|
constructor(
|
|
144
|
-
input: FetchInput<Schema,
|
|
145
|
-
|
|
168
|
+
input: FetchInput<Schema, Method, Path>,
|
|
169
|
+
init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>,
|
|
146
170
|
) {
|
|
147
|
-
const
|
|
171
|
+
const initWithDefaults = { ...defaults, ...init };
|
|
172
|
+
|
|
173
|
+
const headersFromDefaults = new HttpHeaders(defaults.headers);
|
|
174
|
+
const headersFromInit = new HttpHeaders((init satisfies RequestInit as RequestInit).headers);
|
|
148
175
|
|
|
149
176
|
let url: URL;
|
|
177
|
+
const baseURL = new URL(initWithDefaults.baseURL);
|
|
150
178
|
|
|
151
179
|
if (input instanceof globalThis.Request) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
180
|
+
// Optimize type checking by narrowing the type of input
|
|
181
|
+
const request = input as globalThis.Request;
|
|
182
|
+
const headersFromRequest = new HttpHeaders(input.headers);
|
|
183
|
+
|
|
184
|
+
initWithDefaults.headers = {
|
|
185
|
+
...headersFromDefaults.toObject(),
|
|
186
|
+
...headersFromRequest.toObject(),
|
|
187
|
+
...headersFromInit.toObject(),
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
super(request, initWithDefaults);
|
|
157
191
|
|
|
158
192
|
url = new URL(input.url);
|
|
159
193
|
} else {
|
|
160
|
-
|
|
194
|
+
initWithDefaults.headers = {
|
|
195
|
+
...headersFromDefaults.toObject(),
|
|
196
|
+
...headersFromInit.toObject(),
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
url = input instanceof URL ? new URL(input) : new URL(joinURL(baseURL, input));
|
|
161
200
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
201
|
+
const searchParamsFromDefaults = new HttpSearchParams(defaults.searchParams);
|
|
202
|
+
const searchParamsFromInit = new HttpSearchParams(initWithDefaults.searchParams);
|
|
165
203
|
|
|
166
|
-
|
|
204
|
+
initWithDefaults.searchParams = {
|
|
205
|
+
...searchParamsFromDefaults.toObject(),
|
|
206
|
+
...searchParamsFromInit.toObject(),
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
url.search = new HttpSearchParams(initWithDefaults.searchParams).toString();
|
|
210
|
+
|
|
211
|
+
super(url, initWithDefaults);
|
|
167
212
|
}
|
|
168
213
|
|
|
169
|
-
|
|
214
|
+
const baseURLWithoutTrailingSlash = baseURL.toString().replace(/\/$/, '');
|
|
215
|
+
|
|
216
|
+
this.path = excludeURLParams(url)
|
|
170
217
|
.toString()
|
|
171
|
-
.replace(
|
|
218
|
+
.replace(baseURLWithoutTrailingSlash, '') as LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>;
|
|
172
219
|
}
|
|
173
220
|
|
|
174
|
-
clone(): Request<
|
|
221
|
+
clone(): Request<Method, Path> {
|
|
175
222
|
const rawClone = super.clone();
|
|
176
223
|
|
|
177
|
-
return new Request<
|
|
178
|
-
rawClone as unknown as FetchInput<Schema,
|
|
224
|
+
return new Request<Method, Path>(
|
|
225
|
+
rawClone as unknown as FetchInput<Schema, Method, Path>,
|
|
179
226
|
rawClone as unknown as FetchRequestInit<
|
|
180
227
|
Schema,
|
|
181
|
-
|
|
182
|
-
Method
|
|
228
|
+
Method,
|
|
229
|
+
LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>
|
|
183
230
|
>,
|
|
184
231
|
);
|
|
185
232
|
}
|
|
@@ -188,11 +235,11 @@ class FetchClient<Schema extends HttpSchema> {
|
|
|
188
235
|
return Request as FetchRequestConstructor<Schema>;
|
|
189
236
|
}
|
|
190
237
|
|
|
191
|
-
isRequest<Path extends HttpSchemaPath<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(
|
|
238
|
+
isRequest<Path extends HttpSchemaPath.Literal<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(
|
|
192
239
|
request: unknown,
|
|
193
|
-
path: Path,
|
|
194
240
|
method: Method,
|
|
195
|
-
|
|
241
|
+
path: Path,
|
|
242
|
+
): request is FetchRequest<Schema, Method, Path> {
|
|
196
243
|
return (
|
|
197
244
|
request instanceof Request &&
|
|
198
245
|
request.method === method &&
|
|
@@ -202,29 +249,29 @@ class FetchClient<Schema extends HttpSchema> {
|
|
|
202
249
|
);
|
|
203
250
|
}
|
|
204
251
|
|
|
205
|
-
isResponse<Path extends HttpSchemaPath<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(
|
|
252
|
+
isResponse<Path extends HttpSchemaPath.Literal<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(
|
|
206
253
|
response: unknown,
|
|
207
|
-
path: Path,
|
|
208
254
|
method: Method,
|
|
209
|
-
|
|
255
|
+
path: Path,
|
|
256
|
+
): response is FetchResponse<Schema, Method, Path> {
|
|
210
257
|
return (
|
|
211
258
|
response instanceof Response &&
|
|
212
259
|
'request' in response &&
|
|
260
|
+
this.isRequest(response.request, method, path) &&
|
|
213
261
|
'error' in response &&
|
|
214
|
-
|
|
262
|
+
(response.error === null || response.error instanceof FetchResponseError)
|
|
215
263
|
);
|
|
216
264
|
}
|
|
217
265
|
|
|
218
|
-
isResponseError<Path extends HttpSchemaPath<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(
|
|
266
|
+
isResponseError<Path extends HttpSchemaPath.Literal<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(
|
|
219
267
|
error: unknown,
|
|
220
|
-
path: Path,
|
|
221
268
|
method: Method,
|
|
222
|
-
|
|
269
|
+
path: Path,
|
|
270
|
+
): error is FetchResponseError<Schema, Method, Path> {
|
|
223
271
|
return (
|
|
224
272
|
error instanceof FetchResponseError &&
|
|
225
|
-
error.request
|
|
226
|
-
|
|
227
|
-
createRegexFromURL(path).test(error.request.path)
|
|
273
|
+
this.isRequest(error.request, method, path) &&
|
|
274
|
+
this.isResponse(error.response, method, path)
|
|
228
275
|
);
|
|
229
276
|
}
|
|
230
277
|
}
|
|
@@ -1,15 +1,56 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HttpSchema, HttpSchemaMethod, HttpSchemaPath } from '@zimic/http';
|
|
2
2
|
|
|
3
3
|
import { FetchRequest, FetchResponse } from '../types/requests';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* An error representing a response with a failure status code (4XX or 5XX).
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import { type HttpSchema } from '@zimic/http';
|
|
10
|
+
* import { createFetch } from '@zimic/fetch';
|
|
11
|
+
*
|
|
12
|
+
* interface User {
|
|
13
|
+
* id: string;
|
|
14
|
+
* username: string;
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
* type Schema = HttpSchema<{
|
|
18
|
+
* '/users/:userId': {
|
|
19
|
+
* GET: {
|
|
20
|
+
* response: {
|
|
21
|
+
* 200: { body: User };
|
|
22
|
+
* 404: { body: { message: string } };
|
|
23
|
+
* };
|
|
24
|
+
* };
|
|
25
|
+
* };
|
|
26
|
+
* }>;
|
|
27
|
+
*
|
|
28
|
+
* const fetch = createFetch<Schema>({
|
|
29
|
+
* baseURL: 'http://localhost:3000',
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* const response = await fetch(`/users/${userId}`, {
|
|
33
|
+
* method: 'GET',
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* if (!response.ok) {
|
|
37
|
+
* console.log(response.status); // 404
|
|
38
|
+
*
|
|
39
|
+
* console.log(response.error); // FetchResponseError<Schema, 'GET', '/users'>
|
|
40
|
+
* console.log(response.error.request); // FetchRequest<Schema, 'GET', '/users'>
|
|
41
|
+
* console.log(response.error.response); // FetchResponse<Schema, 'GET', '/users'>
|
|
42
|
+
* }
|
|
43
|
+
*
|
|
44
|
+
* @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerror `FetchResponseError` API reference}
|
|
45
|
+
*/
|
|
5
46
|
class FetchResponseError<
|
|
6
|
-
|
|
7
|
-
Method extends
|
|
8
|
-
|
|
47
|
+
Schema extends HttpSchema,
|
|
48
|
+
Method extends HttpSchemaMethod<Schema>,
|
|
49
|
+
Path extends HttpSchemaPath.Literal<Schema, Method>,
|
|
9
50
|
> extends Error {
|
|
10
51
|
constructor(
|
|
11
|
-
public request: FetchRequest<
|
|
12
|
-
public response: FetchResponse<
|
|
52
|
+
public request: FetchRequest<Schema, Method, Path>,
|
|
53
|
+
public response: FetchResponse<Schema, Method, Path, true, 'manual'>,
|
|
13
54
|
) {
|
|
14
55
|
super(`${request.method} ${request.url} failed with status ${response.status}: ${response.statusText}`);
|
|
15
56
|
this.name = 'FetchResponseError';
|
package/src/client/factory.ts
CHANGED
|
@@ -1,12 +1,63 @@
|
|
|
1
1
|
import { HttpSchema } from '@zimic/http';
|
|
2
2
|
|
|
3
3
|
import FetchClient from './FetchClient';
|
|
4
|
-
import { FetchOptions, Fetch
|
|
4
|
+
import { FetchOptions, Fetch } from './types/public';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Creates a {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch fetch instance} typed with an HTTP
|
|
8
|
+
* schema, closely compatible with the {@link https://developer.mozilla.org/docs/Web/API/Fetch_API native Fetch API}. All
|
|
9
|
+
* requests and responses are typed by default with the schema, including methods, paths, status codes, parameters, and
|
|
10
|
+
* bodies.
|
|
11
|
+
*
|
|
12
|
+
* Requests sent by the fetch instance have their URL automatically prefixed with the base URL of the instance.
|
|
13
|
+
* {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch.defaults Default options} are also applied to the
|
|
14
|
+
* requests, if provided.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* import { type HttpSchema } from '@zimic/http';
|
|
18
|
+
* import { createFetch } from '@zimic/fetch';
|
|
19
|
+
*
|
|
20
|
+
* interface User {
|
|
21
|
+
* id: string;
|
|
22
|
+
* username: string;
|
|
23
|
+
* }
|
|
24
|
+
*
|
|
25
|
+
* type Schema = HttpSchema<{
|
|
26
|
+
* '/users': {
|
|
27
|
+
* POST: {
|
|
28
|
+
* request: {
|
|
29
|
+
* headers: { 'content-type': 'application/json' };
|
|
30
|
+
* body: { username: string };
|
|
31
|
+
* };
|
|
32
|
+
* response: {
|
|
33
|
+
* 201: { body: User };
|
|
34
|
+
* };
|
|
35
|
+
* };
|
|
36
|
+
*
|
|
37
|
+
* GET: {
|
|
38
|
+
* request: {
|
|
39
|
+
* searchParams: {
|
|
40
|
+
* query?: string;
|
|
41
|
+
* page?: number;
|
|
42
|
+
* limit?: number;
|
|
43
|
+
* };
|
|
44
|
+
* };
|
|
45
|
+
* response: {
|
|
46
|
+
* 200: { body: User[] };
|
|
47
|
+
* };
|
|
48
|
+
* };
|
|
49
|
+
* };
|
|
50
|
+
* }>;
|
|
51
|
+
*
|
|
52
|
+
* const fetch = createFetch<Schema>({
|
|
53
|
+
* baseURL: 'http://localhost:3000',
|
|
54
|
+
* });
|
|
55
|
+
*
|
|
56
|
+
* @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#createfetch `createFetch(options)` API reference}
|
|
57
|
+
* @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch `fetch` API reference}
|
|
58
|
+
*/
|
|
59
|
+
function createFetch<Schema extends HttpSchema>(options: FetchOptions<Schema>): Fetch<Schema> {
|
|
60
|
+
const { fetch } = new FetchClient<Schema>(options);
|
|
10
61
|
return fetch;
|
|
11
62
|
}
|
|
12
63
|
|
package/src/client/types/json.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
const value = Symbol.for('JSONStringified.value');
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Represents a value stringified by `JSON.stringify`, maintaining a reference to the original type.
|
|
5
|
+
*
|
|
6
|
+
* This type is used to validate that the expected stringified body is passed to `fetch`.
|
|
7
|
+
*
|
|
8
|
+
* @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#using-a-json-body}
|
|
9
|
+
*/
|
|
3
10
|
export type JSONStringified<Value> = string & { [value]: Value };
|
|
4
11
|
|
|
5
12
|
declare global {
|