@ioka-technologies/asyncapi-ts-client-template 0.0.7 โ 0.0.10
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 +468 -122
- package/examples/auth-retry/README.md +384 -0
- package/examples/auth-retry/asyncapi.yaml +464 -0
- package/examples/auth-retry/login-flow-example.ts +375 -0
- package/package.json +3 -2
- package/template/helpers/security.js +137 -0
- package/template/src/client.ts.js +24 -2
- package/template/src/models.ts.js +157 -17
- package/template/src/runtime/auth/headers.ts.js +95 -0
- package/template/src/runtime/auth/index.ts.js +15 -0
- package/template/src/runtime/auth/types.ts.js +74 -0
- package/template/src/runtime/retry/index.ts.js +18 -0
- package/template/src/runtime/retry/manager.ts.js +150 -0
- package/template/src/runtime/retry/presets.ts.js +81 -0
- package/template/src/runtime/retry/types.ts.js +60 -0
- package/template/src/runtime/transports/http.ts.js +112 -17
- package/template/src/runtime/transports/websocket.ts.js +28 -3
- package/template/src/runtime/types.ts.js +12 -3
package/README.md
CHANGED
|
@@ -1,163 +1,424 @@
|
|
|
1
|
-
# TypeScript AsyncAPI Client Generator
|
|
1
|
+
# TypeScript AsyncAPI Client Generator
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Type safety across the network boundary - the missing piece of full-stack AsyncAPI development**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This template solves the fundamental challenge of maintaining type safety and API consistency between async servers and their clients. Instead of hand-writing clients that drift out of sync, we generate **production-ready TypeScript clients** that automatically stay in perfect alignment with your AsyncAPI servers.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- ๐ **Multiple Transports**: WebSocket and HTTP support with automatic transport selection
|
|
9
|
-
- ๐ก๏ธ **Type Safe**: Full TypeScript support with generated interfaces from AsyncAPI schemas
|
|
10
|
-
- ๐ง **Smart Method Names**: Automatic sanitization of operation names to valid JavaScript identifiers
|
|
11
|
-
- ๐ **Auto Reconnection**: WebSocket reconnection with configurable retry logic
|
|
12
|
-
- ๐ **Authentication**: JWT, API Key, and custom authentication support
|
|
13
|
-
- โก **Promise Based**: Modern async/await API
|
|
14
|
-
- ๐ฆ **Zero Config**: Works out of the box with sensible defaults
|
|
15
|
-
- ๐งช **Well Tested**: Comprehensive examples and documentation
|
|
7
|
+
## ๐ฏ The Full-Stack Vision
|
|
16
8
|
|
|
17
|
-
|
|
9
|
+
**The Problem**: Traditional async API development breaks down at the client boundary. You have a perfectly typed server, but clients are hand-written, error-prone, and constantly fall out of sync with server changes.
|
|
18
10
|
|
|
19
|
-
|
|
11
|
+
**Our Solution**: **Automatic Type-Safe Client Generation**
|
|
20
12
|
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
```typescript
|
|
14
|
+
// Generated client with perfect server compatibility
|
|
15
|
+
const client = new ChatClient({
|
|
16
|
+
transport: 'websocket', // or 'http' - same interface
|
|
17
|
+
websocket: { url: 'wss://api.example.com', reconnect: true }
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Type-safe method calls with IntelliSense
|
|
21
|
+
const user = await client.createUser({
|
|
22
|
+
name: "John", // โ
TypeScript knows this is required
|
|
23
|
+
email: "john@...", // โ
TypeScript validates email format
|
|
24
|
+
age: 25 // โ
TypeScript knows this is optional
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Response is fully typed - no runtime surprises
|
|
28
|
+
console.log(user.id); // โ
TypeScript provides autocomplete
|
|
29
|
+
console.log(user.createdAt); // โ
TypeScript knows this is a Date
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Why This Changes Everything**:
|
|
33
|
+
- ๐ **Perfect Sync**: Client and server types are generated from the same AsyncAPI spec
|
|
34
|
+
- ๐ก๏ธ **Compile-Time Safety**: Catch API mismatches before they reach production
|
|
35
|
+
- ๐ **Zero Configuration**: Works out of the box with intelligent defaults
|
|
36
|
+
- ๐ **Transport Agnostic**: Same code works over WebSocket or HTTP
|
|
37
|
+
- ๐ **Production Ready**: Built-in reconnection, error handling, and monitoring
|
|
38
|
+
|
|
39
|
+
## ๐ The 2-Minute Full-Stack Experience
|
|
40
|
+
|
|
41
|
+
**Goal**: Experience the power of synchronized client-server development.
|
|
23
42
|
|
|
24
|
-
###
|
|
43
|
+
### The Business Scenario
|
|
44
|
+
You have a Rust AsyncAPI server handling user management. You need web and mobile clients that stay perfectly in sync as the API evolves.
|
|
25
45
|
|
|
46
|
+
### Step 1: Generate Type-Safe Client (30 seconds)
|
|
26
47
|
```bash
|
|
27
48
|
# Install AsyncAPI CLI
|
|
28
49
|
npm install -g @asyncapi/cli
|
|
29
50
|
|
|
30
|
-
# Generate
|
|
31
|
-
asyncapi generate fromTemplate
|
|
51
|
+
# Generate client from the SAME spec as your Rust server
|
|
52
|
+
asyncapi generate fromTemplate your-user-api.yaml ./ts-client -o user-client
|
|
32
53
|
|
|
33
|
-
# Install
|
|
34
|
-
cd
|
|
35
|
-
|
|
54
|
+
# Install and build
|
|
55
|
+
cd user-client && npm install && npm run build
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Step 2: Use in Your Application (1 minute)
|
|
59
|
+
```typescript
|
|
60
|
+
// React/Vue/Angular - works everywhere
|
|
61
|
+
import { UserApiClient } from './user-client';
|
|
62
|
+
|
|
63
|
+
const client = new UserApiClient({
|
|
64
|
+
transport: 'websocket',
|
|
65
|
+
websocket: {
|
|
66
|
+
url: 'wss://api.yourcompany.com',
|
|
67
|
+
auth: { jwt: getAuthToken() },
|
|
68
|
+
reconnect: true // Production-ready resilience
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Type-safe API calls with IntelliSense
|
|
73
|
+
const App = () => {
|
|
74
|
+
const [users, setUsers] = useState([]);
|
|
75
|
+
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
client.connect();
|
|
78
|
+
|
|
79
|
+
// Real-time updates
|
|
80
|
+
client.onUserCreated((user) => {
|
|
81
|
+
setUsers(prev => [...prev, user]);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
return () => client.disconnect();
|
|
85
|
+
}, []);
|
|
86
|
+
|
|
87
|
+
const createUser = async (userData) => {
|
|
88
|
+
// Fully type-safe - catches errors at compile time
|
|
89
|
+
const newUser = await client.createUser({
|
|
90
|
+
name: userData.name, // Required field
|
|
91
|
+
email: userData.email, // Validated format
|
|
92
|
+
preferences: { // Nested object support
|
|
93
|
+
newsletter: true,
|
|
94
|
+
theme: 'dark'
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Response is fully typed
|
|
99
|
+
console.log(`Created user ${newUser.id} at ${newUser.createdAt}`);
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Step 3: Experience the Magic (30 seconds)
|
|
105
|
+
```bash
|
|
106
|
+
# Server team updates AsyncAPI spec (adds new field)
|
|
107
|
+
# Regenerate client
|
|
108
|
+
asyncapi generate fromTemplate updated-api.yaml ./ts-client -o user-client --force-write
|
|
109
|
+
|
|
110
|
+
# TypeScript compiler immediately shows what changed
|
|
36
111
|
npm run build
|
|
112
|
+
# โ
New fields are available with IntelliSense
|
|
113
|
+
# โ
Removed fields cause compile errors (catch before production)
|
|
114
|
+
# โ
Changed types are automatically updated
|
|
37
115
|
```
|
|
38
116
|
|
|
39
|
-
|
|
117
|
+
**Result**: Your client and server are always perfectly synchronized. API changes are caught at compile time, not in production.
|
|
118
|
+
|
|
119
|
+
## ๐ Generated Client Architecture
|
|
120
|
+
|
|
121
|
+
**The Strategic Design**: Every generated file serves the full-stack development experience.
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
user-client/ # Your generated TypeScript client
|
|
125
|
+
โโโ package.json # NPM package ready for publishing
|
|
126
|
+
โโโ tsconfig.json # TypeScript configuration
|
|
127
|
+
โโโ README.md # Client-specific documentation
|
|
128
|
+
โโโ USAGE.md # Integration examples
|
|
129
|
+
โโโ src/
|
|
130
|
+
โ โโโ index.ts # Public API exports
|
|
131
|
+
โ โโโ client.ts # Main client class
|
|
132
|
+
โ โโโ models.ts # Generated TypeScript interfaces
|
|
133
|
+
โ โโโ transports.ts # Transport layer exports
|
|
134
|
+
โ โโโ runtime/ # Production-ready runtime
|
|
135
|
+
โ โโโ types.ts # Core type definitions
|
|
136
|
+
โ โโโ errors.ts # Typed error classes
|
|
137
|
+
โ โโโ transports/ # Transport implementations
|
|
138
|
+
โ โโโ factory.ts # Intelligent transport selection
|
|
139
|
+
โ โโโ websocket.ts # Real-time WebSocket transport
|
|
140
|
+
โ โโโ http.ts # Reliable HTTP transport
|
|
141
|
+
โโโ examples/ # Ready-to-run examples
|
|
142
|
+
โ โโโ websocket-example.ts # WebSocket integration
|
|
143
|
+
โ โโโ http-example.ts # HTTP integration
|
|
144
|
+
โ โโโ react-example.tsx # React component example
|
|
145
|
+
โโโ dist/ # Compiled JavaScript (after build)
|
|
146
|
+
โโโ index.js # ES modules
|
|
147
|
+
โโโ index.d.ts # TypeScript declarations
|
|
148
|
+
โโโ ... # All compiled outputs
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### The Architecture Strategy
|
|
152
|
+
|
|
153
|
+
**Generated Types** (src/models.ts): Perfect server compatibility
|
|
154
|
+
- **Synchronized**: Generated from the same AsyncAPI spec as your Rust server
|
|
155
|
+
- **Type-safe**: Catch mismatches at compile time, not runtime
|
|
156
|
+
- **Rich**: Support for nested objects, enums, optional fields, validation
|
|
157
|
+
|
|
158
|
+
**Transport Layer** (src/runtime/transports/): Production resilience
|
|
159
|
+
- **WebSocket**: Real-time communication with automatic reconnection
|
|
160
|
+
- **HTTP**: Reliable request/response with retry logic
|
|
161
|
+
- **Unified Interface**: Same API regardless of transport choice
|
|
162
|
+
|
|
163
|
+
**Client Class** (src/client.ts): Developer experience
|
|
164
|
+
- **IntelliSense**: Full autocomplete for all operations
|
|
165
|
+
- **Promise-based**: Modern async/await patterns
|
|
166
|
+
- **Event-driven**: Subscribe to real-time updates
|
|
167
|
+
- **Error handling**: Typed exceptions for robust error handling
|
|
40
168
|
|
|
169
|
+
### Integration Patterns
|
|
170
|
+
|
|
171
|
+
**React/Vue/Angular Integration**:
|
|
172
|
+
```typescript
|
|
173
|
+
// Hook-based integration
|
|
174
|
+
const useUserApi = () => {
|
|
175
|
+
const [client] = useState(() => new UserApiClient({
|
|
176
|
+
transport: 'websocket',
|
|
177
|
+
websocket: { url: process.env.REACT_APP_API_URL }
|
|
178
|
+
}));
|
|
179
|
+
|
|
180
|
+
useEffect(() => {
|
|
181
|
+
client.connect();
|
|
182
|
+
return () => client.disconnect();
|
|
183
|
+
}, []);
|
|
184
|
+
|
|
185
|
+
return client;
|
|
186
|
+
};
|
|
41
187
|
```
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
โโโ PackageJson.js # Package.json generator
|
|
55
|
-
โโโ IndexFile.js # Main index.ts generator
|
|
56
|
-
โโโ ClientFile.js # Client class generator
|
|
57
|
-
โโโ ModelsFile.js # Type definitions generator
|
|
58
|
-
โโโ TransportsFile.js # Transport exports
|
|
59
|
-
โโโ TsConfigFile.js # TypeScript config generator
|
|
60
|
-
โโโ ReadmeFile.js # Generated README
|
|
61
|
-
โโโ UsageFile.js # Generated usage docs
|
|
62
|
-
โโโ examples/ # Example generators
|
|
63
|
-
โ โโโ WebSocketExample.js # WebSocket example generator
|
|
64
|
-
โ โโโ HttpExample.js # HTTP example generator
|
|
65
|
-
โโโ runtime/ # Runtime implementation generators
|
|
66
|
-
โโโ RuntimeTypes.js # Core type definitions
|
|
67
|
-
โโโ RuntimeErrors.js # Error classes
|
|
68
|
-
โโโ TransportFactory.js # Transport factory
|
|
69
|
-
โโโ WebSocketTransport.js # WebSocket implementation
|
|
70
|
-
โโโ HttpTransport.js # HTTP implementation
|
|
188
|
+
|
|
189
|
+
**Node.js Backend Integration**:
|
|
190
|
+
```typescript
|
|
191
|
+
// Server-to-server communication
|
|
192
|
+
const apiClient = new UserApiClient({
|
|
193
|
+
transport: 'http',
|
|
194
|
+
http: {
|
|
195
|
+
baseUrl: 'https://internal-api.company.com',
|
|
196
|
+
auth: { apiKey: process.env.API_KEY },
|
|
197
|
+
retry: { attempts: 3, backoff: 'exponential' }
|
|
198
|
+
}
|
|
199
|
+
});
|
|
71
200
|
```
|
|
72
201
|
|
|
73
|
-
|
|
202
|
+
**Mobile App Integration**:
|
|
203
|
+
```typescript
|
|
204
|
+
// React Native / Expo
|
|
205
|
+
const client = new UserApiClient({
|
|
206
|
+
transport: 'websocket',
|
|
207
|
+
websocket: {
|
|
208
|
+
url: 'wss://api.company.com',
|
|
209
|
+
auth: { jwt: await getStoredToken() },
|
|
210
|
+
reconnect: true,
|
|
211
|
+
reconnectInterval: 5000
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## ๐ง Configuration: Tailored for Your Stack
|
|
217
|
+
|
|
218
|
+
**Strategic Configuration**: Every parameter serves a specific architectural purpose.
|
|
74
219
|
|
|
75
|
-
| Parameter | Type | Default |
|
|
76
|
-
|
|
77
|
-
| `clientName` | string | `"{{info.title}}Client"` |
|
|
78
|
-
| `packageName` | string | `"{{info.title | kebabCase}}-client"` |
|
|
79
|
-
| `packageVersion` | string | `"{{info.version}}"` |
|
|
80
|
-
| `author` | string | `"AsyncAPI Generator"` |
|
|
81
|
-
| `license` | string | `"Apache-2.0"` |
|
|
82
|
-
| `
|
|
83
|
-
| `
|
|
84
|
-
| `
|
|
220
|
+
| Parameter | Type | Default | Purpose |
|
|
221
|
+
|-----------|------|---------|---------|
|
|
222
|
+
| `clientName` | string | `"{{info.title}}Client"` | **Class naming**: Controls the main client class name for your codebase |
|
|
223
|
+
| `packageName` | string | `"{{info.title | kebabCase}}-client"` | **NPM publishing**: Package name for internal/public npm registry |
|
|
224
|
+
| `packageVersion` | string | `"{{info.version}}"` | **Versioning**: Syncs client version with AsyncAPI spec version |
|
|
225
|
+
| `author` | string | `"AsyncAPI Generator"` | **Attribution**: Your team/company name for package metadata |
|
|
226
|
+
| `license` | string | `"Apache-2.0"` | **Legal**: License for your generated client package |
|
|
227
|
+
| `transports` | string | `"websocket,http"` | **Architecture**: Which transport layers to include |
|
|
228
|
+
| `generateTests` | boolean | `true` | **Quality**: Include comprehensive test suite |
|
|
229
|
+
| `includeExamples` | boolean | `true` | **Developer Experience**: Include integration examples |
|
|
85
230
|
|
|
86
|
-
###
|
|
231
|
+
### Real-World Configuration Examples
|
|
87
232
|
|
|
233
|
+
**Enterprise Microservice Client**:
|
|
88
234
|
```bash
|
|
89
|
-
asyncapi generate fromTemplate
|
|
90
|
-
-o
|
|
91
|
-
-p clientName=
|
|
92
|
-
-p packageName
|
|
93
|
-
-p packageVersion=1.0
|
|
94
|
-
-p author="
|
|
95
|
-
-p transports=
|
|
235
|
+
asyncapi generate fromTemplate user-service.yaml ./ts-client \
|
|
236
|
+
-o @company/user-service-client \
|
|
237
|
+
-p clientName=UserServiceClient \
|
|
238
|
+
-p packageName=@company/user-service-client \
|
|
239
|
+
-p packageVersion=2.1.0 \
|
|
240
|
+
-p author="Platform Team <platform@company.com>" \
|
|
241
|
+
-p transports=http \
|
|
242
|
+
-p generateTests=true
|
|
96
243
|
```
|
|
97
244
|
|
|
98
|
-
|
|
245
|
+
**Real-Time Web Application Client**:
|
|
246
|
+
```bash
|
|
247
|
+
asyncapi generate fromTemplate chat-api.yaml ./ts-client \
|
|
248
|
+
-o chat-web-client \
|
|
249
|
+
-p clientName=ChatClient \
|
|
250
|
+
-p packageName=chat-web-client \
|
|
251
|
+
-p transports=websocket \
|
|
252
|
+
-p includeExamples=true
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**Mobile App Client**:
|
|
256
|
+
```bash
|
|
257
|
+
asyncapi generate fromTemplate mobile-api.yaml ./ts-client \
|
|
258
|
+
-o @myapp/api-client \
|
|
259
|
+
-p clientName=MobileApiClient \
|
|
260
|
+
-p packageName=@myapp/api-client \
|
|
261
|
+
-p transports=websocket,http \
|
|
262
|
+
-p generateTests=false \
|
|
263
|
+
-p includeExamples=true
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**IoT Dashboard Client**:
|
|
267
|
+
```bash
|
|
268
|
+
asyncapi generate fromTemplate iot-telemetry.yaml ./ts-client \
|
|
269
|
+
-o iot-dashboard-client \
|
|
270
|
+
-p clientName=IoTDashboardClient \
|
|
271
|
+
-p transports=websocket \
|
|
272
|
+
-p author="IoT Team" \
|
|
273
|
+
-p license=MIT
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## ๐จ The Message Envelope: Cross-Language Compatibility
|
|
99
277
|
|
|
100
|
-
|
|
278
|
+
**The Innovation**: A standardized message format that enables perfect compatibility between Rust servers and TypeScript clients, regardless of transport protocol.
|
|
101
279
|
|
|
102
|
-
|
|
280
|
+
**Why This Matters**: Traditional async APIs suffer from protocol-specific message formats. Our envelope provides a universal standard that works across WebSocket, HTTP, MQTT, and any future transport.
|
|
281
|
+
|
|
282
|
+
### Universal Message Structure
|
|
103
283
|
|
|
104
284
|
```typescript
|
|
105
285
|
interface MessageEnvelope {
|
|
106
|
-
operation: string; // AsyncAPI operation ID
|
|
107
|
-
id?: string; // Correlation ID for request/response
|
|
108
|
-
channel?: string; //
|
|
109
|
-
payload: any; //
|
|
110
|
-
timestamp?: number; // Message
|
|
111
|
-
error?: { //
|
|
112
|
-
code: string;
|
|
113
|
-
message: string;
|
|
286
|
+
operation: string; // AsyncAPI operation ID for routing
|
|
287
|
+
id?: string; // Correlation ID for request/response tracking
|
|
288
|
+
channel?: string; // Channel context for debugging and routing
|
|
289
|
+
payload: any; // Strongly-typed message payload
|
|
290
|
+
timestamp?: number; // Message timing for analytics
|
|
291
|
+
error?: { // Standardized error format
|
|
292
|
+
code: string; // Machine-readable error code
|
|
293
|
+
message: string; // Human-readable error message
|
|
114
294
|
};
|
|
115
295
|
}
|
|
116
296
|
```
|
|
117
297
|
|
|
118
|
-
|
|
298
|
+
**The Architecture Benefits**:
|
|
299
|
+
- ๐ **Operation Routing**: Servers route messages based on operation field
|
|
300
|
+
- ๐ฏ **Request/Response Correlation**: Built-in correlation ID support
|
|
301
|
+
- ๐ก๏ธ **Standardized Errors**: Consistent error handling across all operations
|
|
302
|
+
- ๐ **Transport Agnostic**: Same envelope works over any protocol
|
|
303
|
+
- ๐ **Observability**: Built-in timing and debugging information
|
|
304
|
+
|
|
305
|
+
### Real-World Message Flows
|
|
119
306
|
|
|
120
|
-
|
|
307
|
+
**The Power**: These patterns work identically whether you're using WebSocket, HTTP, or any other transport.
|
|
308
|
+
|
|
309
|
+
#### Enterprise User Management Flow
|
|
121
310
|
```typescript
|
|
122
|
-
// Client
|
|
311
|
+
// 1. Client Request (WebSocket or HTTP - same format)
|
|
123
312
|
{
|
|
124
|
-
"operation": "
|
|
125
|
-
"id": "
|
|
126
|
-
"channel": "user/
|
|
127
|
-
"payload": {
|
|
128
|
-
|
|
313
|
+
"operation": "createUser",
|
|
314
|
+
"id": "req_789abc",
|
|
315
|
+
"channel": "user/management",
|
|
316
|
+
"payload": {
|
|
317
|
+
"name": "Sarah Johnson",
|
|
318
|
+
"email": "sarah@company.com",
|
|
319
|
+
"department": "Engineering",
|
|
320
|
+
"role": "Senior Developer"
|
|
321
|
+
},
|
|
322
|
+
"timestamp": 1640995200000
|
|
129
323
|
}
|
|
130
324
|
|
|
131
|
-
// Server
|
|
325
|
+
// 2. Server Success Response
|
|
132
326
|
{
|
|
133
|
-
"operation": "
|
|
134
|
-
"id": "
|
|
135
|
-
"payload": {
|
|
136
|
-
|
|
327
|
+
"operation": "createUser",
|
|
328
|
+
"id": "req_789abc",
|
|
329
|
+
"payload": {
|
|
330
|
+
"userId": "usr_456def",
|
|
331
|
+
"name": "Sarah Johnson",
|
|
332
|
+
"email": "sarah@company.com",
|
|
333
|
+
"createdAt": "2021-12-31T12:00:00Z",
|
|
334
|
+
"onboardingTasks": [
|
|
335
|
+
"complete_profile",
|
|
336
|
+
"setup_2fa",
|
|
337
|
+
"join_team_channels"
|
|
338
|
+
]
|
|
339
|
+
},
|
|
340
|
+
"timestamp": 1640995201500
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// 3. Real-Time Notification (to other users)
|
|
344
|
+
{
|
|
345
|
+
"operation": "userJoined",
|
|
346
|
+
"channel": "team/notifications",
|
|
347
|
+
"payload": {
|
|
348
|
+
"userId": "usr_456def",
|
|
349
|
+
"name": "Sarah Johnson",
|
|
350
|
+
"department": "Engineering",
|
|
351
|
+
"joinedAt": "2021-12-31T12:00:00Z"
|
|
352
|
+
},
|
|
353
|
+
"timestamp": 1640995201600
|
|
137
354
|
}
|
|
138
355
|
```
|
|
139
356
|
|
|
140
|
-
####
|
|
357
|
+
#### Error Handling with Business Context
|
|
141
358
|
```typescript
|
|
142
|
-
//
|
|
359
|
+
// Business Logic Error
|
|
143
360
|
{
|
|
144
|
-
"operation": "
|
|
145
|
-
"
|
|
146
|
-
"
|
|
147
|
-
|
|
361
|
+
"operation": "createUser",
|
|
362
|
+
"id": "req_789abc",
|
|
363
|
+
"error": {
|
|
364
|
+
"code": "EMAIL_ALREADY_EXISTS",
|
|
365
|
+
"message": "A user with email sarah@company.com already exists"
|
|
366
|
+
},
|
|
367
|
+
"timestamp": 1640995201000
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Validation Error
|
|
371
|
+
{
|
|
372
|
+
"operation": "createUser",
|
|
373
|
+
"id": "req_789abc",
|
|
374
|
+
"error": {
|
|
375
|
+
"code": "VALIDATION_FAILED",
|
|
376
|
+
"message": "Invalid email format: not-an-email"
|
|
377
|
+
},
|
|
378
|
+
"timestamp": 1640995201000
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Infrastructure Error
|
|
382
|
+
{
|
|
383
|
+
"operation": "createUser",
|
|
384
|
+
"id": "req_789abc",
|
|
385
|
+
"error": {
|
|
386
|
+
"code": "SERVICE_UNAVAILABLE",
|
|
387
|
+
"message": "User database is temporarily unavailable"
|
|
388
|
+
},
|
|
389
|
+
"timestamp": 1640995201000
|
|
148
390
|
}
|
|
149
391
|
```
|
|
150
392
|
|
|
151
|
-
####
|
|
393
|
+
#### IoT Telemetry Stream
|
|
152
394
|
```typescript
|
|
395
|
+
// Sensor Data (MQTT โ WebSocket bridge)
|
|
153
396
|
{
|
|
154
|
-
"operation": "
|
|
155
|
-
"
|
|
156
|
-
"
|
|
157
|
-
"
|
|
158
|
-
"
|
|
397
|
+
"operation": "sensorReading",
|
|
398
|
+
"channel": "sensors/temperature",
|
|
399
|
+
"payload": {
|
|
400
|
+
"sensorId": "temp_001",
|
|
401
|
+
"location": "server_room_a",
|
|
402
|
+
"temperature": 23.5,
|
|
403
|
+
"humidity": 45.2,
|
|
404
|
+
"batteryLevel": 87
|
|
405
|
+
},
|
|
406
|
+
"timestamp": 1640995202000
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Alert Trigger
|
|
410
|
+
{
|
|
411
|
+
"operation": "alertTriggered",
|
|
412
|
+
"channel": "alerts/critical",
|
|
413
|
+
"payload": {
|
|
414
|
+
"alertId": "alert_456",
|
|
415
|
+
"type": "TEMPERATURE_HIGH",
|
|
416
|
+
"sensorId": "temp_001",
|
|
417
|
+
"currentValue": 35.8,
|
|
418
|
+
"threshold": 30.0,
|
|
419
|
+
"severity": "CRITICAL"
|
|
159
420
|
},
|
|
160
|
-
"timestamp":
|
|
421
|
+
"timestamp": 1640995203000
|
|
161
422
|
}
|
|
162
423
|
```
|
|
163
424
|
|
|
@@ -256,38 +517,123 @@ const response = await client.getUserProfile({
|
|
|
256
517
|
console.log(response.user.name); // TypeScript provides autocomplete
|
|
257
518
|
```
|
|
258
519
|
|
|
259
|
-
## ๐ Authentication Support
|
|
520
|
+
## ๐ Authentication & Retry Support
|
|
521
|
+
|
|
522
|
+
The generated client includes comprehensive authentication and retry capabilities inspired by the Rust server template.
|
|
260
523
|
|
|
261
|
-
### JWT
|
|
524
|
+
### JWT Authentication
|
|
262
525
|
|
|
263
526
|
```typescript
|
|
264
|
-
{
|
|
527
|
+
const client = new MyServiceClient({
|
|
528
|
+
transport: 'http',
|
|
529
|
+
url: 'https://api.example.com',
|
|
265
530
|
auth: {
|
|
266
|
-
|
|
531
|
+
jwt: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
|
267
532
|
}
|
|
268
|
-
}
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
// JWT token is automatically added to Authorization header
|
|
536
|
+
const response = await client.getUserProfile({ userId: '123' });
|
|
269
537
|
```
|
|
270
538
|
|
|
271
|
-
###
|
|
539
|
+
### Basic Authentication
|
|
272
540
|
|
|
273
541
|
```typescript
|
|
274
|
-
{
|
|
542
|
+
const client = new MyServiceClient({
|
|
543
|
+
transport: 'http',
|
|
544
|
+
url: 'https://api.example.com',
|
|
275
545
|
auth: {
|
|
276
|
-
|
|
546
|
+
basic: {
|
|
547
|
+
username: 'myuser',
|
|
548
|
+
password: 'mypassword'
|
|
549
|
+
}
|
|
277
550
|
}
|
|
278
|
-
}
|
|
551
|
+
});
|
|
279
552
|
```
|
|
280
553
|
|
|
281
|
-
###
|
|
554
|
+
### API Key Authentication
|
|
282
555
|
|
|
283
556
|
```typescript
|
|
284
|
-
|
|
557
|
+
// API Key in header
|
|
558
|
+
const client = new MyServiceClient({
|
|
559
|
+
transport: 'http',
|
|
560
|
+
url: 'https://api.example.com',
|
|
285
561
|
auth: {
|
|
286
|
-
|
|
287
|
-
|
|
562
|
+
apikey: {
|
|
563
|
+
key: 'my-api-key-123',
|
|
564
|
+
location: 'header',
|
|
565
|
+
name: 'X-API-Key'
|
|
288
566
|
}
|
|
289
567
|
}
|
|
290
|
-
}
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
// API Key in query parameter
|
|
571
|
+
const client2 = new MyServiceClient({
|
|
572
|
+
transport: 'http',
|
|
573
|
+
url: 'https://api.example.com',
|
|
574
|
+
auth: {
|
|
575
|
+
apikey: {
|
|
576
|
+
key: 'my-api-key-123',
|
|
577
|
+
location: 'query',
|
|
578
|
+
name: 'apikey'
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
});
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
### Retry Configuration
|
|
585
|
+
|
|
586
|
+
```typescript
|
|
587
|
+
// Using retry presets
|
|
588
|
+
const client = new MyServiceClient({
|
|
589
|
+
transport: 'http',
|
|
590
|
+
url: 'https://api.example.com',
|
|
591
|
+
retry: 'balanced' // 'conservative', 'balanced', 'aggressive', or 'none'
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
// Custom retry configuration
|
|
595
|
+
const client2 = new MyServiceClient({
|
|
596
|
+
transport: 'http',
|
|
597
|
+
url: 'https://api.example.com',
|
|
598
|
+
retry: {
|
|
599
|
+
enabled: true,
|
|
600
|
+
maxAttempts: 3,
|
|
601
|
+
baseDelay: 1000,
|
|
602
|
+
maxDelay: 30000,
|
|
603
|
+
backoffMultiplier: 2,
|
|
604
|
+
jitter: true,
|
|
605
|
+
retryableStatusCodes: [429, 500, 502, 503, 504],
|
|
606
|
+
retryableErrors: ['NETWORK_ERROR', 'TIMEOUT']
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
// Per-request retry override
|
|
611
|
+
const response = await client.createUser(userData, {
|
|
612
|
+
retry: 'aggressive',
|
|
613
|
+
timeout: 10000
|
|
614
|
+
});
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### Auth Error Handling
|
|
618
|
+
|
|
619
|
+
```typescript
|
|
620
|
+
const client = new MyServiceClient({
|
|
621
|
+
transport: 'http',
|
|
622
|
+
url: 'https://api.example.com',
|
|
623
|
+
auth: { jwt: 'your-token' },
|
|
624
|
+
authCallbacks: {
|
|
625
|
+
onAuthError: async () => {
|
|
626
|
+
// Handle 401 errors - refresh token, etc.
|
|
627
|
+
console.log('Authentication failed, attempting to refresh...');
|
|
628
|
+
return false; // Return true to retry with updated auth
|
|
629
|
+
}
|
|
630
|
+
},
|
|
631
|
+
retryCallbacks: {
|
|
632
|
+
onRetry: (attempt, error, delay) => {
|
|
633
|
+
console.log(`Retry attempt ${attempt} after ${delay}ms`);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
});
|
|
291
637
|
```
|
|
292
638
|
|
|
293
639
|
## ๐ Error Handling
|