@tahanabavi/typefetch 1.0.3 → 1.1.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/README.md +131 -10
- package/dist/index.d.mts +22 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +4044 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4056 -22
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# TypeFetch
|
|
2
2
|
|
|
3
|
-
TypeFetch is a type-safe client for working with APIs, built with TypeScript and Zod. This project allows you to define API contracts and safely use types, while also supporting middlewares, error handling, and response
|
|
3
|
+
TypeFetch is a type-safe client for working with APIs, built with TypeScript and Zod. This project allows you to define API contracts and safely use types, while also supporting middlewares, error handling, response transformation, mock data, and response wrappers.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -12,6 +12,8 @@ TypeFetch is a type-safe client for working with APIs, built with TypeScript and
|
|
|
12
12
|
- Error handling with the `RichError` class
|
|
13
13
|
- Ability to transform responses using a response transformer
|
|
14
14
|
- Authentication support via token
|
|
15
|
+
- Mock data support for development and testing
|
|
16
|
+
- Response wrapper for consistent API response formats
|
|
15
17
|
|
|
16
18
|
---
|
|
17
19
|
|
|
@@ -25,9 +27,39 @@ yarn add @tahanabavi/typefetch
|
|
|
25
27
|
|
|
26
28
|
---
|
|
27
29
|
|
|
30
|
+
## What's New in v1.1.1
|
|
31
|
+
|
|
32
|
+
### 🎯 Mock Data Support
|
|
33
|
+
|
|
34
|
+
- Add mock data to endpoints for development and testing
|
|
35
|
+
- Configurable random delays to simulate network latency
|
|
36
|
+
- Support for both static data and dynamic functions
|
|
37
|
+
- Runtime toggle between mock and real API modes
|
|
38
|
+
|
|
39
|
+
### 🔄 Response Wrapper
|
|
40
|
+
|
|
41
|
+
- Consistent API response format handling
|
|
42
|
+
- Automatic validation of wrapped responses
|
|
43
|
+
- Support for success/error response patterns
|
|
44
|
+
- Seamless integration with existing contracts
|
|
45
|
+
|
|
46
|
+
### 🚀 Enhanced Error Handling
|
|
47
|
+
|
|
48
|
+
- Better Zod error wrapping and reporting
|
|
49
|
+
- Improved type safety for response wrappers
|
|
50
|
+
|
|
51
|
+
### 🔧 Token Provider System
|
|
52
|
+
|
|
53
|
+
- Dynamic token resolution: Tokens resolved at request time, not initialization
|
|
54
|
+
- Universal compatibility: Works seamlessly in both server and client environments
|
|
55
|
+
- Async token providers: Support for asynchronous token retrieval
|
|
56
|
+
- Multiple token sources: Flexible token sourcing from cookies, context, or external services
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
28
60
|
## Defining Contracts
|
|
29
61
|
|
|
30
|
-
Contracts are defined using the `Contracts` and `EndpointDef` types
|
|
62
|
+
Contracts are defined using the `Contracts` and `EndpointDef` types.
|
|
31
63
|
|
|
32
64
|
```ts
|
|
33
65
|
import { z } from "zod";
|
|
@@ -40,12 +72,16 @@ const contracts = {
|
|
|
40
72
|
auth: true,
|
|
41
73
|
request: z.object({ id: z.string() }),
|
|
42
74
|
response: z.object({ id: z.string(), name: z.string() }),
|
|
75
|
+
// Optional mock data
|
|
76
|
+
mockData: { id: "1", name: "John Doe" },
|
|
43
77
|
},
|
|
44
78
|
createUser: {
|
|
45
79
|
method: "POST",
|
|
46
80
|
path: "/user",
|
|
47
81
|
request: z.object({ name: z.string() }),
|
|
48
82
|
response: z.object({ id: z.string(), name: z.string() }),
|
|
83
|
+
// Dynamic mock data function
|
|
84
|
+
mockData: () => ({ id: Math.random().toString(), name: "Dynamic User" }),
|
|
49
85
|
},
|
|
50
86
|
},
|
|
51
87
|
} as const;
|
|
@@ -62,6 +98,8 @@ const client = new ApiClient(
|
|
|
62
98
|
{
|
|
63
99
|
baseUrl: "https://api.example.com",
|
|
64
100
|
token: "your-auth-token",
|
|
101
|
+
useMockData: true,
|
|
102
|
+
mockDelay: { min: 100, max: 1000 },
|
|
65
103
|
},
|
|
66
104
|
contracts
|
|
67
105
|
);
|
|
@@ -82,7 +120,7 @@ All errors are provided via the `RichError` class. You can define a custom error
|
|
|
82
120
|
|
|
83
121
|
```ts
|
|
84
122
|
client.onError((error: RichError) => {
|
|
85
|
-
console.error("API Error:", error.message, error.status);
|
|
123
|
+
console.error("API Error:", error.message, error.status, error.code);
|
|
86
124
|
});
|
|
87
125
|
```
|
|
88
126
|
|
|
@@ -140,11 +178,61 @@ client.useResponseTransform((data) => {
|
|
|
140
178
|
|
|
141
179
|
---
|
|
142
180
|
|
|
181
|
+
## Mock Data Features
|
|
182
|
+
|
|
183
|
+
Static Mock Data:
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
mockData: { id: "1", name: "Static User" }
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Dynamic Mock Data:
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
mockData: () => ({ id: Math.random().toString(), name: `User-${Date.now()}` });
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Runtime Control:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
client.setMockMode(true, { min: 100, max: 2000 });
|
|
199
|
+
client.setMockMode(false);
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Response Wrapper Features
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
const apiResponseWrapper = (successResponse: z.ZodTypeAny) =>
|
|
208
|
+
z.union([
|
|
209
|
+
z.object({
|
|
210
|
+
success: z.literal(true),
|
|
211
|
+
data: successResponse,
|
|
212
|
+
timestamp: z.string(),
|
|
213
|
+
requestId: z.string(),
|
|
214
|
+
}),
|
|
215
|
+
z.object({
|
|
216
|
+
success: z.literal(false),
|
|
217
|
+
message: z.string(),
|
|
218
|
+
code: z.number(),
|
|
219
|
+
timestamp: z.string(),
|
|
220
|
+
requestId: z.string(),
|
|
221
|
+
}),
|
|
222
|
+
]);
|
|
223
|
+
|
|
224
|
+
client.setResponseWrapper(apiResponseWrapper);
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
143
229
|
## Important Notes
|
|
144
230
|
|
|
145
231
|
- Always call `client.init()` before using endpoints.
|
|
146
232
|
- Types are automatically inferred from Zod, making inputs and outputs type-safe.
|
|
147
233
|
- Middleware execution order: first added middleware runs last, last added middleware runs first.
|
|
234
|
+
- Mock data is used only when `useMockData` is true and mock data is defined.
|
|
235
|
+
- Response wrapper automatically handles success/error patterns.
|
|
148
236
|
|
|
149
237
|
---
|
|
150
238
|
|
|
@@ -156,23 +244,50 @@ import { ApiClient, RichError } from "typefetch";
|
|
|
156
244
|
import { LoggingMiddleware, RetryMiddleware } from "typefetch/middlewares";
|
|
157
245
|
|
|
158
246
|
const contracts = {
|
|
159
|
-
|
|
160
|
-
|
|
247
|
+
user: {
|
|
248
|
+
getUser: {
|
|
161
249
|
method: "GET",
|
|
162
|
-
path: "/
|
|
250
|
+
path: "/users/:id",
|
|
163
251
|
auth: true,
|
|
164
252
|
request: z.object({ id: z.string() }),
|
|
165
|
-
response: z.object({
|
|
253
|
+
response: z.object({
|
|
254
|
+
id: z.string(),
|
|
255
|
+
name: z.string(),
|
|
256
|
+
email: z.string(),
|
|
257
|
+
}),
|
|
258
|
+
mockData: { id: "1", name: "John Doe", email: "john@example.com" },
|
|
166
259
|
},
|
|
167
260
|
},
|
|
168
261
|
} as const;
|
|
169
262
|
|
|
263
|
+
const apiResponseWrapper = (successResponse: z.ZodTypeAny) =>
|
|
264
|
+
z.union([
|
|
265
|
+
z.object({
|
|
266
|
+
success: z.literal(true),
|
|
267
|
+
data: successResponse,
|
|
268
|
+
timestamp: z.string(),
|
|
269
|
+
requestId: z.string(),
|
|
270
|
+
}),
|
|
271
|
+
z.object({
|
|
272
|
+
success: z.literal(false),
|
|
273
|
+
message: z.string(),
|
|
274
|
+
code: z.number(),
|
|
275
|
+
timestamp: z.string(),
|
|
276
|
+
requestId: z.string(),
|
|
277
|
+
}),
|
|
278
|
+
]);
|
|
279
|
+
|
|
170
280
|
const client = new ApiClient(
|
|
171
|
-
{
|
|
281
|
+
{
|
|
282
|
+
baseUrl: "https://api.example.com",
|
|
283
|
+
token: "abc123",
|
|
284
|
+
useMockData: process.env.NODE_ENV === "development",
|
|
285
|
+
},
|
|
172
286
|
contracts
|
|
173
287
|
);
|
|
174
288
|
|
|
175
289
|
client.init();
|
|
290
|
+
client.setResponseWrapper(apiResponseWrapper);
|
|
176
291
|
client.use(LoggingMiddleware);
|
|
177
292
|
client.use(RetryMiddleware, { maxRetries: 2 });
|
|
178
293
|
|
|
@@ -183,7 +298,13 @@ client.onError((err: RichError) => {
|
|
|
183
298
|
const { modules: api } = client;
|
|
184
299
|
|
|
185
300
|
(async () => {
|
|
186
|
-
const
|
|
187
|
-
console.log(
|
|
301
|
+
const user = await api.user.getUser({ id: "1" });
|
|
302
|
+
console.log(user);
|
|
188
303
|
})();
|
|
189
304
|
```
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## License
|
|
309
|
+
|
|
310
|
+
MIT
|
package/dist/index.d.mts
CHANGED
|
@@ -6,6 +6,7 @@ type EndpointDef<TReq extends z.ZodTypeAny, TRes extends z.ZodTypeAny> = {
|
|
|
6
6
|
auth?: boolean;
|
|
7
7
|
request: TReq;
|
|
8
8
|
response: TRes;
|
|
9
|
+
mockData?: (() => z.infer<TRes>) | z.infer<TRes>;
|
|
9
10
|
};
|
|
10
11
|
type Contracts = {
|
|
11
12
|
[ModuleName: string]: {
|
|
@@ -28,6 +29,7 @@ type EndpointDefZ = EndpointDef<z.ZodTypeAny, z.ZodTypeAny>;
|
|
|
28
29
|
type EndpointMethods<M extends Record<string, EndpointDefZ>> = {
|
|
29
30
|
[K in keyof M]: (input: z.infer<M[K]["request"]>) => Promise<z.infer<M[K]["response"]>>;
|
|
30
31
|
};
|
|
32
|
+
type TokenProvider = () => string | Promise<string>;
|
|
31
33
|
|
|
32
34
|
declare class RichError extends Error implements ErrorLike {
|
|
33
35
|
status?: number;
|
|
@@ -45,17 +47,36 @@ declare class ApiClient<C extends Contracts, E extends ErrorLike = RichError> {
|
|
|
45
47
|
private middlewares;
|
|
46
48
|
private errorHandler?;
|
|
47
49
|
private responseTransform;
|
|
50
|
+
private useMockData;
|
|
51
|
+
private mockDelay;
|
|
52
|
+
private responseWrapper?;
|
|
53
|
+
private tokenProvider?;
|
|
48
54
|
private _modules;
|
|
49
55
|
constructor(config: {
|
|
50
56
|
baseUrl: string;
|
|
51
57
|
token?: string;
|
|
58
|
+
tokenProvider?: TokenProvider;
|
|
59
|
+
useMockData?: boolean;
|
|
60
|
+
mockDelay?: {
|
|
61
|
+
min: number;
|
|
62
|
+
max: number;
|
|
63
|
+
};
|
|
52
64
|
}, contracts: C);
|
|
53
65
|
init(): void;
|
|
54
66
|
get modules(): { [M in keyof C]: EndpointMethods<C[M]>; };
|
|
55
67
|
use<T>(middleware: Middleware<T>, options?: T): void;
|
|
56
68
|
onError(handler: (error: E) => void): void;
|
|
57
69
|
useResponseTransform(fn: (data: any) => any): void;
|
|
70
|
+
setMockMode(enabled: boolean, delay?: {
|
|
71
|
+
min: number;
|
|
72
|
+
max: number;
|
|
73
|
+
}): void;
|
|
74
|
+
setResponseWrapper(wrapper: (successResponse: z.ZodTypeAny) => z.ZodTypeAny): void;
|
|
75
|
+
setTokenProvider(provider: TokenProvider): void;
|
|
76
|
+
getCurrentToken(): Promise<string | undefined>;
|
|
58
77
|
private request;
|
|
78
|
+
private handleMockRequest;
|
|
79
|
+
private getRandomDelay;
|
|
59
80
|
private createError;
|
|
60
81
|
private normalizeError;
|
|
61
82
|
}
|
|
@@ -83,4 +104,4 @@ type CacheOptions = {
|
|
|
83
104
|
};
|
|
84
105
|
declare const cacheMiddleware: (options?: CacheOptions) => (ctx: MiddlewareContext, next: MiddlewareNext) => Promise<Response>;
|
|
85
106
|
|
|
86
|
-
export { ApiClient, type AuthOptions, type CacheOptions, type Contracts, type EndpointDef, type EndpointDefZ, type EndpointMethods, type ErrorLike, type LoggingOptions, type Middleware, type MiddlewareContext, type MiddlewareNext, type RetryOptions, RichError, authMiddleware, cacheMiddleware, loggingMiddleware, retryMiddleware };
|
|
107
|
+
export { ApiClient, type AuthOptions, type CacheOptions, type Contracts, type EndpointDef, type EndpointDefZ, type EndpointMethods, type ErrorLike, type LoggingOptions, type Middleware, type MiddlewareContext, type MiddlewareNext, type RetryOptions, RichError, type TokenProvider, authMiddleware, cacheMiddleware, loggingMiddleware, retryMiddleware };
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ type EndpointDef<TReq extends z.ZodTypeAny, TRes extends z.ZodTypeAny> = {
|
|
|
6
6
|
auth?: boolean;
|
|
7
7
|
request: TReq;
|
|
8
8
|
response: TRes;
|
|
9
|
+
mockData?: (() => z.infer<TRes>) | z.infer<TRes>;
|
|
9
10
|
};
|
|
10
11
|
type Contracts = {
|
|
11
12
|
[ModuleName: string]: {
|
|
@@ -28,6 +29,7 @@ type EndpointDefZ = EndpointDef<z.ZodTypeAny, z.ZodTypeAny>;
|
|
|
28
29
|
type EndpointMethods<M extends Record<string, EndpointDefZ>> = {
|
|
29
30
|
[K in keyof M]: (input: z.infer<M[K]["request"]>) => Promise<z.infer<M[K]["response"]>>;
|
|
30
31
|
};
|
|
32
|
+
type TokenProvider = () => string | Promise<string>;
|
|
31
33
|
|
|
32
34
|
declare class RichError extends Error implements ErrorLike {
|
|
33
35
|
status?: number;
|
|
@@ -45,17 +47,36 @@ declare class ApiClient<C extends Contracts, E extends ErrorLike = RichError> {
|
|
|
45
47
|
private middlewares;
|
|
46
48
|
private errorHandler?;
|
|
47
49
|
private responseTransform;
|
|
50
|
+
private useMockData;
|
|
51
|
+
private mockDelay;
|
|
52
|
+
private responseWrapper?;
|
|
53
|
+
private tokenProvider?;
|
|
48
54
|
private _modules;
|
|
49
55
|
constructor(config: {
|
|
50
56
|
baseUrl: string;
|
|
51
57
|
token?: string;
|
|
58
|
+
tokenProvider?: TokenProvider;
|
|
59
|
+
useMockData?: boolean;
|
|
60
|
+
mockDelay?: {
|
|
61
|
+
min: number;
|
|
62
|
+
max: number;
|
|
63
|
+
};
|
|
52
64
|
}, contracts: C);
|
|
53
65
|
init(): void;
|
|
54
66
|
get modules(): { [M in keyof C]: EndpointMethods<C[M]>; };
|
|
55
67
|
use<T>(middleware: Middleware<T>, options?: T): void;
|
|
56
68
|
onError(handler: (error: E) => void): void;
|
|
57
69
|
useResponseTransform(fn: (data: any) => any): void;
|
|
70
|
+
setMockMode(enabled: boolean, delay?: {
|
|
71
|
+
min: number;
|
|
72
|
+
max: number;
|
|
73
|
+
}): void;
|
|
74
|
+
setResponseWrapper(wrapper: (successResponse: z.ZodTypeAny) => z.ZodTypeAny): void;
|
|
75
|
+
setTokenProvider(provider: TokenProvider): void;
|
|
76
|
+
getCurrentToken(): Promise<string | undefined>;
|
|
58
77
|
private request;
|
|
78
|
+
private handleMockRequest;
|
|
79
|
+
private getRandomDelay;
|
|
59
80
|
private createError;
|
|
60
81
|
private normalizeError;
|
|
61
82
|
}
|
|
@@ -83,4 +104,4 @@ type CacheOptions = {
|
|
|
83
104
|
};
|
|
84
105
|
declare const cacheMiddleware: (options?: CacheOptions) => (ctx: MiddlewareContext, next: MiddlewareNext) => Promise<Response>;
|
|
85
106
|
|
|
86
|
-
export { ApiClient, type AuthOptions, type CacheOptions, type Contracts, type EndpointDef, type EndpointDefZ, type EndpointMethods, type ErrorLike, type LoggingOptions, type Middleware, type MiddlewareContext, type MiddlewareNext, type RetryOptions, RichError, authMiddleware, cacheMiddleware, loggingMiddleware, retryMiddleware };
|
|
107
|
+
export { ApiClient, type AuthOptions, type CacheOptions, type Contracts, type EndpointDef, type EndpointDefZ, type EndpointMethods, type ErrorLike, type LoggingOptions, type Middleware, type MiddlewareContext, type MiddlewareNext, type RetryOptions, RichError, type TokenProvider, authMiddleware, cacheMiddleware, loggingMiddleware, retryMiddleware };
|