tapi-rs 3.0.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 +281 -0
- package/dist/core.d.ts +65 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +169 -0
- package/dist/core.js.map +1 -0
- package/dist/endpoints.d.ts +63 -0
- package/dist/endpoints.d.ts.map +1 -0
- package/dist/endpoints.js +44 -0
- package/dist/endpoints.js.map +1 -0
- package/dist/errors.d.ts +36 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +43 -0
- package/dist/errors.js.map +1 -0
- package/dist/hook.d.ts +10 -0
- package/dist/hook.d.ts.map +1 -0
- package/dist/hook.js +99 -0
- package/dist/hook.js.map +1 -0
- package/dist/index.d.ts +213 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/request.d.ts +5 -0
- package/dist/request.d.ts.map +1 -0
- package/dist/request.js +109 -0
- package/dist/request.js.map +1 -0
- package/dist/response.d.ts +27 -0
- package/dist/response.d.ts.map +1 -0
- package/dist/response.js +4 -0
- package/dist/response.js.map +1 -0
- package/dist/translations.d.ts +17 -0
- package/dist/translations.d.ts.map +1 -0
- package/dist/translations.js +35 -0
- package/dist/translations.js.map +1 -0
- package/dist/types.d.ts +105 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +84 -0
- package/dist/utils.js.map +1 -0
- package/package.json +66 -0
package/README.md
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# Tapi
|
|
2
|
+
|
|
3
|
+
A type-safe REST API client builder for TypeScript with React hooks integration.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Type Safety** - Full TypeScript support with compile-time type checking
|
|
8
|
+
- **Error as Value** - No thrown errors, all errors returned as discriminated unions
|
|
9
|
+
- **React Hooks** - Built-in React integration with loading states
|
|
10
|
+
- **Zero Runtime Validation** - Pure TypeScript types, no runtime overhead
|
|
11
|
+
- **Lightweight** - No external validation library dependencies
|
|
12
|
+
- **Auto-completion** - Full IDE support with IntelliSense
|
|
13
|
+
- **Internationalization** - Multi-language support for error messages
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install tapi
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import Tapi from "tapi";
|
|
25
|
+
|
|
26
|
+
// 1. Define your types
|
|
27
|
+
type User = {
|
|
28
|
+
id: number;
|
|
29
|
+
name: string;
|
|
30
|
+
email: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// 2. Build your API client
|
|
34
|
+
const api = Tapi.builder()
|
|
35
|
+
.withHost("https://api.example.com")
|
|
36
|
+
.withApiError(async (res) => ({ code: res.status, message: res.statusText }))
|
|
37
|
+
.withRoutes({
|
|
38
|
+
users: {
|
|
39
|
+
getAll: Tapi.get<{ response: User[] }>()({
|
|
40
|
+
endpoint: "/users",
|
|
41
|
+
response: Tapi.response<User[]>()
|
|
42
|
+
}),
|
|
43
|
+
getById: Tapi.get<{ path: { id: string }; response: User }>()({
|
|
44
|
+
endpoint: "/users/:id",
|
|
45
|
+
response: Tapi.response<User>()
|
|
46
|
+
}),
|
|
47
|
+
create: Tapi.post<{ body: { name: string; email: string }; response: User }>()({
|
|
48
|
+
endpoint: "/users",
|
|
49
|
+
response: Tapi.response<User>()
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
.build();
|
|
54
|
+
|
|
55
|
+
// 3. Use it
|
|
56
|
+
const result = await api.users.getAll({});
|
|
57
|
+
if (result.ok) {
|
|
58
|
+
console.log(result.data); // Fully typed User[]
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Type Parameters
|
|
63
|
+
|
|
64
|
+
Tapi uses object-based type parameters - only specify what you need:
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// Simple - just response type
|
|
68
|
+
Tapi.get<{ response: User[] }>();
|
|
69
|
+
|
|
70
|
+
// With path params
|
|
71
|
+
Tapi.get<{ path: { id: string }; response: User }>();
|
|
72
|
+
|
|
73
|
+
// With query params
|
|
74
|
+
Tapi.get<{ query: { limit?: number }; response: Post[] }>();
|
|
75
|
+
|
|
76
|
+
// With body (for POST/PUT/PATCH)
|
|
77
|
+
Tapi.post<{ body: CreateUser; response: User }>();
|
|
78
|
+
|
|
79
|
+
// With headers
|
|
80
|
+
Tapi.get<{ headers: { Authorization: string }; response: User }>();
|
|
81
|
+
|
|
82
|
+
// With formData
|
|
83
|
+
Tapi.post<{ formData: { file: File }; response: UploadResult }>();
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Error Handling
|
|
87
|
+
|
|
88
|
+
All API calls return a discriminated union with an `ok` boolean:
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
const result = await api.users.getById({ path: { id: "123" } });
|
|
92
|
+
|
|
93
|
+
if (result.ok) {
|
|
94
|
+
console.log("User:", result.data);
|
|
95
|
+
} else {
|
|
96
|
+
switch (result.status) {
|
|
97
|
+
case "network_error":
|
|
98
|
+
console.error("Network failed:", result.error);
|
|
99
|
+
break;
|
|
100
|
+
case "api_error":
|
|
101
|
+
console.error(`API error [${result.code}]:`, result.data);
|
|
102
|
+
break;
|
|
103
|
+
case "mapper_error":
|
|
104
|
+
console.error("Mapper failed:", result.error);
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## React Integration
|
|
111
|
+
|
|
112
|
+
Use the built-in React hooks for automatic loading states:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
function UserProfile({ userId }: { userId: string }) {
|
|
116
|
+
const [user, error, loading, refresh, setUser] = api.users.getById.useHook({
|
|
117
|
+
path: { id: userId }
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
if (loading) return <div>Loading...</div>;
|
|
121
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<div>
|
|
125
|
+
<h1>{user.name}</h1>
|
|
126
|
+
<p>{user.email}</p>
|
|
127
|
+
<button onClick={() => refresh()}>Refresh</button>
|
|
128
|
+
</div>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Hook Return Value
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
const [data, error, loading, refresh, setter] = api.endpoint.useHook(params);
|
|
137
|
+
|
|
138
|
+
// data - The response data (null if loading or error)
|
|
139
|
+
// error - The error object (null if success or loading)
|
|
140
|
+
// loading - Boolean loading state
|
|
141
|
+
// refresh - Function to refetch (pass true to reset state)
|
|
142
|
+
// setter - Function to update data locally
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Lazy Loading
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
const [user, error, loading, refresh] = api.users.getById.useHook({
|
|
149
|
+
path: { id: userId },
|
|
150
|
+
lazy: true // Don't fetch on mount
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Trigger fetch manually
|
|
154
|
+
<button onClick={() => refresh(true)}>Load User</button>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Response Mappers
|
|
158
|
+
|
|
159
|
+
Transform API responses with type-safe mappers:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
type ApiUser = { id: number; full_name: string };
|
|
163
|
+
type User = { id: number; name: string };
|
|
164
|
+
|
|
165
|
+
const api = Tapi.builder()
|
|
166
|
+
.withHost("https://api.example.com")
|
|
167
|
+
.withApiError(async (res) => ({ code: res.status }))
|
|
168
|
+
.withRoutes({
|
|
169
|
+
users: {
|
|
170
|
+
getById: Tapi.get<{
|
|
171
|
+
path: { id: string };
|
|
172
|
+
response: ApiUser;
|
|
173
|
+
mapped: User;
|
|
174
|
+
}>()({
|
|
175
|
+
endpoint: "/users/:id",
|
|
176
|
+
response: Tapi.response<ApiUser, User>((data) => () => ({
|
|
177
|
+
id: data.id,
|
|
178
|
+
name: data.full_name
|
|
179
|
+
}))
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
.build();
|
|
184
|
+
|
|
185
|
+
// result.data is typed as User (mapped type)
|
|
186
|
+
const result = await api.users.getById({ path: { id: "123" } });
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Mappers with Arguments
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
const api = Tapi.builder()
|
|
193
|
+
.withHost("https://api.example.com")
|
|
194
|
+
.withApiError(async (res) => ({ code: res.status }))
|
|
195
|
+
.withRoutes({
|
|
196
|
+
posts: {
|
|
197
|
+
getAll: Tapi.get<{
|
|
198
|
+
response: Post[];
|
|
199
|
+
mapped: Post[];
|
|
200
|
+
mapArg: { limit: number };
|
|
201
|
+
}>()({
|
|
202
|
+
endpoint: "/posts",
|
|
203
|
+
response: Tapi.response<Post[], Post[], { limit: number }>((posts) => (args) => posts.slice(0, args.limit))
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
})
|
|
207
|
+
.build();
|
|
208
|
+
|
|
209
|
+
// Pass mapper arguments at call time
|
|
210
|
+
const result = await api.posts.getAll({ map: { limit: 5 } });
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Advanced Configuration
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
const api = Tapi.builder()
|
|
217
|
+
.withHost("https://api.example.com")
|
|
218
|
+
.withApiError(async (response) => {
|
|
219
|
+
const error = await response.json();
|
|
220
|
+
return {
|
|
221
|
+
message: error.message || "Unknown error",
|
|
222
|
+
code: response.status,
|
|
223
|
+
details: error
|
|
224
|
+
};
|
|
225
|
+
})
|
|
226
|
+
.withDefaultHeaders({
|
|
227
|
+
Authorization: "Bearer <token>",
|
|
228
|
+
"Content-Type": "application/json"
|
|
229
|
+
})
|
|
230
|
+
.withPrefetch((request) => {
|
|
231
|
+
console.log(`[${request.method}] ${request.url}`);
|
|
232
|
+
})
|
|
233
|
+
.withPostfetch((response) => {
|
|
234
|
+
if (!response.ok) {
|
|
235
|
+
console.error("Request failed:", response.status);
|
|
236
|
+
}
|
|
237
|
+
})
|
|
238
|
+
.withLanguage("en") // "en" | "br"
|
|
239
|
+
.withRoutes(routes)
|
|
240
|
+
.build();
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Dynamic Headers
|
|
244
|
+
|
|
245
|
+
Update headers at runtime using `setHeaders`:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// Update auth token
|
|
249
|
+
api.setHeaders({
|
|
250
|
+
Authorization: `Bearer ${newToken}`
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Also works on nested routes
|
|
254
|
+
api.users.setHeaders({ ... });
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Internationalization
|
|
258
|
+
|
|
259
|
+
Tapi supports multiple languages for error messages:
|
|
260
|
+
|
|
261
|
+
- `"en"` - English (default)
|
|
262
|
+
- `"br"` - Portuguese (Brazil)
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
const api = Tapi.builder()
|
|
266
|
+
.withHost("https://api.example.com")
|
|
267
|
+
.withLanguage("br") // Portuguese error messages
|
|
268
|
+
.withApiError(async (res) => res.statusText)
|
|
269
|
+
.withRoutes(routes)
|
|
270
|
+
.build();
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Examples
|
|
274
|
+
|
|
275
|
+
Check the `examples/` folder for comprehensive examples:
|
|
276
|
+
|
|
277
|
+
- **`tapi-example.ts`** - Complete API client with all features
|
|
278
|
+
|
|
279
|
+
## License
|
|
280
|
+
|
|
281
|
+
MIT
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as Hook from "./hook";
|
|
2
|
+
import { Language } from "./translations";
|
|
3
|
+
import * as Types from "./types";
|
|
4
|
+
type RouteFunction<T extends Types.RequestConfig<any, any, any, any, any, any, any, any, any>, TError = string> = Types.RequesterFunction<T, TError> & {
|
|
5
|
+
useHook: (params: Types.CallSignature<T>) => Hook.HookResponse<T, TError>;
|
|
6
|
+
};
|
|
7
|
+
export type GenerateApiMethods<T extends Types.RouteDefinitions, TError = string> = {
|
|
8
|
+
[K in keyof T]: T[K] extends Types.RequestConfig<any, any, any, any, any, any, any, any, any> ? RouteFunction<T[K], TError> : T[K] extends Types.RouteDefinitions ? GenerateApiMethods<T[K], TError> : never;
|
|
9
|
+
} & {
|
|
10
|
+
/**
|
|
11
|
+
* Update default headers for all requests in this API instance
|
|
12
|
+
*/
|
|
13
|
+
setHeaders: (headers: Record<string, string>) => void;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Builder class for creating API methods with proper type inference and compile-time validation
|
|
17
|
+
*/
|
|
18
|
+
export declare class TapiBuilder<TRoutes extends Types.RouteDefinitions = {}, TError = string, THasHost extends boolean = false, THasRoutes extends boolean = false, THasErrorHandler extends boolean = false> {
|
|
19
|
+
private host?;
|
|
20
|
+
private routes?;
|
|
21
|
+
private prefetchCallback?;
|
|
22
|
+
private postfetchCallback?;
|
|
23
|
+
private defaultHeaders?;
|
|
24
|
+
private errorHandler?;
|
|
25
|
+
private language;
|
|
26
|
+
/**
|
|
27
|
+
* Set the host URL for API requests
|
|
28
|
+
*/
|
|
29
|
+
withHost(host: string): TapiBuilder<TRoutes, TError, true, THasRoutes, THasErrorHandler>;
|
|
30
|
+
/**
|
|
31
|
+
* Set the route definitions with proper type inference
|
|
32
|
+
*/
|
|
33
|
+
withRoutes<T extends Types.RouteDefinitions>(routes: T): TapiBuilder<T, TError, THasHost, true, THasErrorHandler>;
|
|
34
|
+
/**
|
|
35
|
+
* Set the error handler with proper type inference
|
|
36
|
+
*/
|
|
37
|
+
withApiError<T>(errorHandler: (response: Response) => Promise<T>): TapiBuilder<TRoutes, T, THasHost, THasRoutes, true>;
|
|
38
|
+
/**
|
|
39
|
+
* Set the prefetch callback that runs before each request
|
|
40
|
+
*/
|
|
41
|
+
withPrefetch(callback: Types.PrefetchCallback): TapiBuilder<TRoutes, TError, THasHost, THasRoutes, THasErrorHandler>;
|
|
42
|
+
/**
|
|
43
|
+
* Set the postfetch callback that runs after each request
|
|
44
|
+
*/
|
|
45
|
+
withPostfetch(callback: Types.PostfetchCallback<any, TError>): TapiBuilder<TRoutes, TError, THasHost, THasRoutes, THasErrorHandler>;
|
|
46
|
+
/**
|
|
47
|
+
* Set default headers for all requests
|
|
48
|
+
*/
|
|
49
|
+
withDefaultHeaders(headers: Record<string, string>): TapiBuilder<TRoutes, TError, THasHost, THasRoutes, THasErrorHandler>;
|
|
50
|
+
/**
|
|
51
|
+
* Set the language for error messages
|
|
52
|
+
*/
|
|
53
|
+
withLanguage(language: Language): TapiBuilder<TRoutes, TError, THasHost, THasRoutes, THasErrorHandler>;
|
|
54
|
+
/**
|
|
55
|
+
* Build the API client with compile-time validation
|
|
56
|
+
*
|
|
57
|
+
* This method enforces that all required configurations are set:
|
|
58
|
+
* - Host URL
|
|
59
|
+
* - Route definitions
|
|
60
|
+
* - Error handler
|
|
61
|
+
*/
|
|
62
|
+
build(...args: THasHost extends false ? ["Host is required - use .withHost() first"] : THasRoutes extends false ? ["Routes are required - use .withRoutes() first"] : THasErrorHandler extends false ? ["Error handler is required - use .withApiError() first"] : []): THasHost extends true ? (THasRoutes extends true ? (THasErrorHandler extends true ? GenerateApiMethods<TRoutes, TError> : never) : never) : never;
|
|
63
|
+
}
|
|
64
|
+
export {};
|
|
65
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}
|
package/dist/core.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import * as Hook from "./hook";
|
|
2
|
+
import * as RequestCreator from "./request";
|
|
3
|
+
/**
|
|
4
|
+
* Check if a value is a RequestConfig by duck-typing
|
|
5
|
+
*/
|
|
6
|
+
function isRequestConfig(value) {
|
|
7
|
+
if (typeof value !== "object" || value === null)
|
|
8
|
+
return false;
|
|
9
|
+
const v = value;
|
|
10
|
+
return typeof v.method === "string" && typeof v.endpoint === "string" && typeof v.response === "object" && v.response !== null;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Recursively creates nested API methods based on route definitions
|
|
14
|
+
*/
|
|
15
|
+
function createNestedMethods(host, routes, target, prefetchCallback, postfetchCallback, defaultHeaders, errorHandler, language = "en") {
|
|
16
|
+
// Store headers and update function references for use by setHeaders method
|
|
17
|
+
let currentHeaders = defaultHeaders;
|
|
18
|
+
const updateTargets = [];
|
|
19
|
+
for (const [routeName, routeValue] of Object.entries(routes)) {
|
|
20
|
+
if (isRequestConfig(routeValue)) {
|
|
21
|
+
const requester = RequestCreator.create(host, routeValue, prefetchCallback, postfetchCallback, currentHeaders, errorHandler, language);
|
|
22
|
+
const hook = (params) => Hook.useHook(requester, params);
|
|
23
|
+
requester.useHook = hook;
|
|
24
|
+
target[routeName] = requester;
|
|
25
|
+
updateTargets.push({ target: routeName, config: routeValue });
|
|
26
|
+
}
|
|
27
|
+
else if (typeof routeValue === "object" && routeValue !== null) {
|
|
28
|
+
target[routeName] = {};
|
|
29
|
+
createNestedMethods(host, routeValue, target[routeName], prefetchCallback, postfetchCallback, currentHeaders, errorHandler, language);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Add setHeaders method to update headers for all nested routes
|
|
33
|
+
target.setHeaders = (headers) => {
|
|
34
|
+
currentHeaders = headers;
|
|
35
|
+
// Update existing routes with new headers
|
|
36
|
+
for (const item of updateTargets) {
|
|
37
|
+
const requester = RequestCreator.create(host, item.config, prefetchCallback, postfetchCallback, headers, errorHandler, language);
|
|
38
|
+
const hook = (params) => Hook.useHook(requester, params);
|
|
39
|
+
requester.useHook = hook;
|
|
40
|
+
target[item.target] = requester;
|
|
41
|
+
}
|
|
42
|
+
// Update headers for nested objects
|
|
43
|
+
for (const key in target) {
|
|
44
|
+
if (target.hasOwnProperty(key) && typeof target[key] === "object" && target[key] !== null && typeof target[key].setHeaders === "function" && key !== "setHeaders") {
|
|
45
|
+
target[key].setHeaders(headers);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Builder class for creating API methods with proper type inference and compile-time validation
|
|
52
|
+
*/
|
|
53
|
+
export class TapiBuilder {
|
|
54
|
+
constructor() {
|
|
55
|
+
this.language = "en";
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Set the host URL for API requests
|
|
59
|
+
*/
|
|
60
|
+
withHost(host) {
|
|
61
|
+
const builder = new TapiBuilder();
|
|
62
|
+
builder.host = host;
|
|
63
|
+
builder.routes = this.routes;
|
|
64
|
+
builder.prefetchCallback = this.prefetchCallback;
|
|
65
|
+
builder.postfetchCallback = this.postfetchCallback;
|
|
66
|
+
builder.defaultHeaders = this.defaultHeaders;
|
|
67
|
+
builder.errorHandler = this.errorHandler;
|
|
68
|
+
builder.language = this.language;
|
|
69
|
+
return builder;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Set the route definitions with proper type inference
|
|
73
|
+
*/
|
|
74
|
+
withRoutes(routes) {
|
|
75
|
+
const builder = new TapiBuilder();
|
|
76
|
+
builder.host = this.host;
|
|
77
|
+
builder.routes = routes;
|
|
78
|
+
builder.prefetchCallback = this.prefetchCallback;
|
|
79
|
+
builder.postfetchCallback = this.postfetchCallback;
|
|
80
|
+
builder.defaultHeaders = this.defaultHeaders;
|
|
81
|
+
builder.errorHandler = this.errorHandler;
|
|
82
|
+
builder.language = this.language;
|
|
83
|
+
return builder;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Set the error handler with proper type inference
|
|
87
|
+
*/
|
|
88
|
+
withApiError(errorHandler) {
|
|
89
|
+
const builder = new TapiBuilder();
|
|
90
|
+
builder.host = this.host;
|
|
91
|
+
builder.routes = this.routes;
|
|
92
|
+
builder.prefetchCallback = this.prefetchCallback;
|
|
93
|
+
builder.postfetchCallback = undefined; // Reset postfetch as error type changed
|
|
94
|
+
builder.defaultHeaders = this.defaultHeaders;
|
|
95
|
+
builder.errorHandler = errorHandler;
|
|
96
|
+
builder.language = this.language;
|
|
97
|
+
return builder;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Set the prefetch callback that runs before each request
|
|
101
|
+
*/
|
|
102
|
+
withPrefetch(callback) {
|
|
103
|
+
const builder = new TapiBuilder();
|
|
104
|
+
builder.host = this.host;
|
|
105
|
+
builder.routes = this.routes;
|
|
106
|
+
builder.prefetchCallback = callback;
|
|
107
|
+
builder.postfetchCallback = this.postfetchCallback;
|
|
108
|
+
builder.defaultHeaders = this.defaultHeaders;
|
|
109
|
+
builder.errorHandler = this.errorHandler;
|
|
110
|
+
builder.language = this.language;
|
|
111
|
+
return builder;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Set the postfetch callback that runs after each request
|
|
115
|
+
*/
|
|
116
|
+
withPostfetch(callback) {
|
|
117
|
+
const builder = new TapiBuilder();
|
|
118
|
+
builder.host = this.host;
|
|
119
|
+
builder.routes = this.routes;
|
|
120
|
+
builder.prefetchCallback = this.prefetchCallback;
|
|
121
|
+
builder.postfetchCallback = callback;
|
|
122
|
+
builder.defaultHeaders = this.defaultHeaders;
|
|
123
|
+
builder.errorHandler = this.errorHandler;
|
|
124
|
+
builder.language = this.language;
|
|
125
|
+
return builder;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Set default headers for all requests
|
|
129
|
+
*/
|
|
130
|
+
withDefaultHeaders(headers) {
|
|
131
|
+
const builder = new TapiBuilder();
|
|
132
|
+
builder.host = this.host;
|
|
133
|
+
builder.routes = this.routes;
|
|
134
|
+
builder.prefetchCallback = this.prefetchCallback;
|
|
135
|
+
builder.postfetchCallback = this.postfetchCallback;
|
|
136
|
+
builder.defaultHeaders = headers;
|
|
137
|
+
builder.errorHandler = this.errorHandler;
|
|
138
|
+
builder.language = this.language;
|
|
139
|
+
return builder;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Set the language for error messages
|
|
143
|
+
*/
|
|
144
|
+
withLanguage(language) {
|
|
145
|
+
const builder = new TapiBuilder();
|
|
146
|
+
builder.host = this.host;
|
|
147
|
+
builder.routes = this.routes;
|
|
148
|
+
builder.prefetchCallback = this.prefetchCallback;
|
|
149
|
+
builder.postfetchCallback = this.postfetchCallback;
|
|
150
|
+
builder.defaultHeaders = this.defaultHeaders;
|
|
151
|
+
builder.errorHandler = this.errorHandler;
|
|
152
|
+
builder.language = language;
|
|
153
|
+
return builder;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Build the API client with compile-time validation
|
|
157
|
+
*
|
|
158
|
+
* This method enforces that all required configurations are set:
|
|
159
|
+
* - Host URL
|
|
160
|
+
* - Route definitions
|
|
161
|
+
* - Error handler
|
|
162
|
+
*/
|
|
163
|
+
build(...args) {
|
|
164
|
+
const apiMethods = {};
|
|
165
|
+
createNestedMethods(this.host, this.routes, apiMethods, this.prefetchCallback, this.postfetchCallback, this.defaultHeaders, this.errorHandler, this.language);
|
|
166
|
+
return apiMethods;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=core.js.map
|
package/dist/core.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { RequestConfig } from "./types";
|
|
2
|
+
import type { ResponseConfig } from "./response";
|
|
3
|
+
/**
|
|
4
|
+
* Configuration object for endpoint factories
|
|
5
|
+
*/
|
|
6
|
+
type EndpointOptions<TResponse, TMapped, TMapArg> = {
|
|
7
|
+
endpoint: string;
|
|
8
|
+
response: ResponseConfig<TResponse, TMapped, TMapArg>;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Type parameters object - only specify what you need
|
|
12
|
+
*/
|
|
13
|
+
type EndpointTypes<TPath = undefined, TBody = undefined, TFormData = undefined, TQuery = undefined, THeaders = undefined, TResponse = unknown, TMapped = TResponse, TMapArg = undefined> = {
|
|
14
|
+
path?: TPath;
|
|
15
|
+
body?: TBody;
|
|
16
|
+
formData?: TFormData;
|
|
17
|
+
query?: TQuery;
|
|
18
|
+
headers?: THeaders;
|
|
19
|
+
response?: TResponse;
|
|
20
|
+
mapped?: TMapped;
|
|
21
|
+
mapArg?: TMapArg;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Extract types from the config object with defaults
|
|
25
|
+
*/
|
|
26
|
+
type ExtractPath<T> = T extends {
|
|
27
|
+
path: infer P;
|
|
28
|
+
} ? P : undefined;
|
|
29
|
+
type ExtractBody<T> = T extends {
|
|
30
|
+
body: infer B;
|
|
31
|
+
} ? B : undefined;
|
|
32
|
+
type ExtractFormData<T> = T extends {
|
|
33
|
+
formData: infer F;
|
|
34
|
+
} ? F : undefined;
|
|
35
|
+
type ExtractQuery<T> = T extends {
|
|
36
|
+
query: infer Q;
|
|
37
|
+
} ? Q : undefined;
|
|
38
|
+
type ExtractHeaders<T> = T extends {
|
|
39
|
+
headers: infer H;
|
|
40
|
+
} ? H : undefined;
|
|
41
|
+
type ExtractResponse<T> = T extends {
|
|
42
|
+
response: infer R;
|
|
43
|
+
} ? R : unknown;
|
|
44
|
+
type ExtractMapped<T> = T extends {
|
|
45
|
+
mapped: infer M;
|
|
46
|
+
} ? M : ExtractResponse<T>;
|
|
47
|
+
type ExtractMapArg<T> = T extends {
|
|
48
|
+
mapArg: infer A;
|
|
49
|
+
} ? A : undefined;
|
|
50
|
+
export declare const get: <T extends EndpointTypes<any, any, any, any, any, any, any, any> = {}>() => (config: EndpointOptions<ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>) => RequestConfig<"GET", ExtractPath<T>, ExtractBody<T>, ExtractFormData<T>, ExtractQuery<T>, ExtractHeaders<T>, ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>;
|
|
51
|
+
export declare const post: <T extends EndpointTypes<any, any, any, any, any, any, any, any> = {}>() => (config: EndpointOptions<ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>) => RequestConfig<"POST", ExtractPath<T>, ExtractBody<T>, ExtractFormData<T>, ExtractQuery<T>, ExtractHeaders<T>, ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>;
|
|
52
|
+
export declare const put: <T extends EndpointTypes<any, any, any, any, any, any, any, any> = {}>() => (config: EndpointOptions<ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>) => RequestConfig<"PUT", ExtractPath<T>, ExtractBody<T>, ExtractFormData<T>, ExtractQuery<T>, ExtractHeaders<T>, ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>;
|
|
53
|
+
export declare const del: <T extends EndpointTypes<any, any, any, any, any, any, any, any> = {}>() => (config: EndpointOptions<ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>) => RequestConfig<"DELETE", ExtractPath<T>, ExtractBody<T>, ExtractFormData<T>, ExtractQuery<T>, ExtractHeaders<T>, ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>;
|
|
54
|
+
export declare const patch: <T extends EndpointTypes<any, any, any, any, any, any, any, any> = {}>() => (config: EndpointOptions<ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>) => RequestConfig<"PATCH", ExtractPath<T>, ExtractBody<T>, ExtractFormData<T>, ExtractQuery<T>, ExtractHeaders<T>, ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>;
|
|
55
|
+
export declare const Endpoints: {
|
|
56
|
+
readonly get: <T extends EndpointTypes<any, any, any, any, any, any, any, any> = {}>() => (config: EndpointOptions<ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>) => RequestConfig<"GET", ExtractPath<T>, ExtractBody<T>, ExtractFormData<T>, ExtractQuery<T>, ExtractHeaders<T>, ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>;
|
|
57
|
+
readonly post: <T extends EndpointTypes<any, any, any, any, any, any, any, any> = {}>() => (config: EndpointOptions<ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>) => RequestConfig<"POST", ExtractPath<T>, ExtractBody<T>, ExtractFormData<T>, ExtractQuery<T>, ExtractHeaders<T>, ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>;
|
|
58
|
+
readonly put: <T extends EndpointTypes<any, any, any, any, any, any, any, any> = {}>() => (config: EndpointOptions<ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>) => RequestConfig<"PUT", ExtractPath<T>, ExtractBody<T>, ExtractFormData<T>, ExtractQuery<T>, ExtractHeaders<T>, ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>;
|
|
59
|
+
readonly delete: <T extends EndpointTypes<any, any, any, any, any, any, any, any> = {}>() => (config: EndpointOptions<ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>) => RequestConfig<"DELETE", ExtractPath<T>, ExtractBody<T>, ExtractFormData<T>, ExtractQuery<T>, ExtractHeaders<T>, ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>;
|
|
60
|
+
readonly patch: <T extends EndpointTypes<any, any, any, any, any, any, any, any> = {}>() => (config: EndpointOptions<ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>) => RequestConfig<"PATCH", ExtractPath<T>, ExtractBody<T>, ExtractFormData<T>, ExtractQuery<T>, ExtractHeaders<T>, ExtractResponse<T>, ExtractMapped<T>, ExtractMapArg<T>>;
|
|
61
|
+
};
|
|
62
|
+
export {};
|
|
63
|
+
//# sourceMappingURL=endpoints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoints.d.ts","sourceRoot":"","sources":["../src/endpoints.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Curried endpoint factory using object-based type parameters
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* // Simple - just response type
|
|
6
|
+
* Tapi.get<{ response: User[] }>()({ endpoint: "/users", response: Tapi.response<User[]>() })
|
|
7
|
+
*
|
|
8
|
+
* // With path params
|
|
9
|
+
* Tapi.get<{ path: { id: string }, response: User }>()({ endpoint: "/users/:id", response: Tapi.response<User>() })
|
|
10
|
+
*
|
|
11
|
+
* // With query params
|
|
12
|
+
* Tapi.get<{ query: { limit?: number }, response: Post[] }>()({ endpoint: "/posts", response: Tapi.response<Post[]>() })
|
|
13
|
+
*
|
|
14
|
+
* // With body (for POST/PUT)
|
|
15
|
+
* Tapi.post<{ body: CreateUser, response: User }>()({ endpoint: "/users", response: Tapi.response<User>() })
|
|
16
|
+
*
|
|
17
|
+
* // With mapper
|
|
18
|
+
* Tapi.get<{ path: { id: string }, response: User, mapped: UserDTO }>()({
|
|
19
|
+
* endpoint: "/users/:id",
|
|
20
|
+
* response: Tapi.response<User, UserDTO>((u) => () => ({ ...u, fullName: u.name }))
|
|
21
|
+
* })
|
|
22
|
+
*/
|
|
23
|
+
function createEndpointFactory(method) {
|
|
24
|
+
return () => (config) => ({
|
|
25
|
+
method,
|
|
26
|
+
endpoint: config.endpoint,
|
|
27
|
+
response: config.response
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
// Individual endpoint factories
|
|
31
|
+
export const get = createEndpointFactory("GET");
|
|
32
|
+
export const post = createEndpointFactory("POST");
|
|
33
|
+
export const put = createEndpointFactory("PUT");
|
|
34
|
+
export const del = createEndpointFactory("DELETE");
|
|
35
|
+
export const patch = createEndpointFactory("PATCH");
|
|
36
|
+
// Namespace export
|
|
37
|
+
export const Endpoints = {
|
|
38
|
+
get,
|
|
39
|
+
post,
|
|
40
|
+
put,
|
|
41
|
+
delete: del,
|
|
42
|
+
patch
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=endpoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoints.js","sourceRoot":"","sources":["../src/endpoints.ts"],"names":[],"mappings":"AA8CA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,SAAS,qBAAqB,CAA6B,MAAe;IACxE,OAAO,GAAyE,EAAE,CAChF,CACE,MAA+E,EAW/E,EAAE,CAAC,CAAC;QACJ,MAAM;QACN,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC1B,CAAC,CAAC;AACP,CAAC;AAED,gCAAgC;AAChC,MAAM,CAAC,MAAM,GAAG,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;AAChD,MAAM,CAAC,MAAM,IAAI,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAClD,MAAM,CAAC,MAAM,GAAG,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;AAChD,MAAM,CAAC,MAAM,GAAG,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;AACnD,MAAM,CAAC,MAAM,KAAK,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAEpD,mBAAmB;AACnB,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,GAAG;IACH,IAAI;IACJ,GAAG;IACH,MAAM,EAAE,GAAG;IACX,KAAK;CACG,CAAC"}
|