@ioka-technologies/asyncapi-ts-client-template 0.0.10 → 0.0.12
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 +98 -620
- package/package.json +2 -1
- package/template/index.js +113 -122
- package/template/src/models.ts.js +11 -3
- package/USAGE.md +0 -586
package/README.md
CHANGED
|
@@ -1,650 +1,152 @@
|
|
|
1
|
-
# TypeScript
|
|
1
|
+
# AsyncAPI TypeScript Client Template
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
⚠️ **Experimental**: This template is still a work in progress and until we reach a 0.1.0 version, assume this is experimental and is not production ready.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Generate type-safe TypeScript clients from your AsyncAPI specifications with automatic transport selection and built-in error handling.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Overview
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
This template generates TypeScript clients that provide full type safety across the network boundary. The generated clients work seamlessly with AsyncAPI servers and automatically handle transport protocols, reconnection logic, and error recovery.
|
|
10
10
|
|
|
11
|
-
**
|
|
11
|
+
**Key Benefits:**
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
websocket: { url: 'wss://api.example.com', reconnect: true }
|
|
18
|
-
});
|
|
13
|
+
- **Type Safety**: Full TypeScript types generated from your AsyncAPI spec
|
|
14
|
+
- **Transport Agnostic**: Same API works over WebSocket or HTTP
|
|
15
|
+
- **Auto Reconnection**: Built-in resilience for production environments
|
|
16
|
+
- **Zero Configuration**: Works out of the box with sensible defaults
|
|
19
17
|
|
|
20
|
-
|
|
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
|
-
});
|
|
18
|
+
## Technical Requirements
|
|
26
19
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
```
|
|
20
|
+
- Node.js 16+
|
|
21
|
+
- TypeScript 4.5+
|
|
22
|
+
- AsyncAPI CLI 1.0+
|
|
31
23
|
|
|
32
|
-
|
|
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
|
|
24
|
+
## Supported Transports
|
|
38
25
|
|
|
39
|
-
|
|
26
|
+
- WebSocket (with auto-reconnection)
|
|
27
|
+
- HTTP (with retry logic)
|
|
40
28
|
|
|
41
|
-
|
|
29
|
+
## Quick Start
|
|
42
30
|
|
|
43
|
-
###
|
|
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.
|
|
31
|
+
### Installation
|
|
45
32
|
|
|
46
|
-
### Step 1: Generate Type-Safe Client (30 seconds)
|
|
47
33
|
```bash
|
|
48
34
|
# Install AsyncAPI CLI
|
|
49
35
|
npm install -g @asyncapi/cli
|
|
50
36
|
|
|
51
|
-
# Generate
|
|
52
|
-
asyncapi generate fromTemplate
|
|
53
|
-
|
|
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';
|
|
37
|
+
# Generate your TypeScript client
|
|
38
|
+
asyncapi generate fromTemplate asyncapi.yaml @ioka-technologies/asyncapi-ts-client-template -o my-client
|
|
62
39
|
|
|
63
|
-
|
|
64
|
-
|
|
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
|
|
40
|
+
cd my-client
|
|
41
|
+
npm install
|
|
111
42
|
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
|
|
115
43
|
```
|
|
116
44
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
## 📁 Generated Client Architecture
|
|
120
|
-
|
|
121
|
-
**The Strategic Design**: Every generated file serves the full-stack development experience.
|
|
45
|
+
### Basic Usage
|
|
122
46
|
|
|
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
|
|
168
|
-
|
|
169
|
-
### Integration Patterns
|
|
170
|
-
|
|
171
|
-
**React/Vue/Angular Integration**:
|
|
172
47
|
```typescript
|
|
173
|
-
|
|
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
|
-
};
|
|
187
|
-
```
|
|
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
|
-
});
|
|
200
|
-
```
|
|
48
|
+
import { MyApiClient } from './my-client';
|
|
201
49
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
// React Native / Expo
|
|
205
|
-
const client = new UserApiClient({
|
|
50
|
+
// WebSocket client with auto-reconnection
|
|
51
|
+
const client = new MyApiClient({
|
|
206
52
|
transport: 'websocket',
|
|
207
53
|
websocket: {
|
|
208
|
-
url: 'wss://api.
|
|
209
|
-
|
|
210
|
-
reconnect: true,
|
|
211
|
-
reconnectInterval: 5000
|
|
54
|
+
url: 'wss://api.example.com',
|
|
55
|
+
reconnect: true
|
|
212
56
|
}
|
|
213
57
|
});
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
## 🔧 Configuration: Tailored for Your Stack
|
|
217
|
-
|
|
218
|
-
**Strategic Configuration**: Every parameter serves a specific architectural purpose.
|
|
219
|
-
|
|
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 |
|
|
230
|
-
|
|
231
|
-
### Real-World Configuration Examples
|
|
232
|
-
|
|
233
|
-
**Enterprise Microservice Client**:
|
|
234
|
-
```bash
|
|
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
|
|
243
|
-
```
|
|
244
|
-
|
|
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
|
|
277
|
-
|
|
278
|
-
**The Innovation**: A standardized message format that enables perfect compatibility between Rust servers and TypeScript clients, regardless of transport protocol.
|
|
279
|
-
|
|
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
|
|
283
|
-
|
|
284
|
-
```typescript
|
|
285
|
-
interface MessageEnvelope {
|
|
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
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
```
|
|
297
|
-
|
|
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
|
|
306
|
-
|
|
307
|
-
**The Power**: These patterns work identically whether you're using WebSocket, HTTP, or any other transport.
|
|
308
|
-
|
|
309
|
-
#### Enterprise User Management Flow
|
|
310
|
-
```typescript
|
|
311
|
-
// 1. Client Request (WebSocket or HTTP - same format)
|
|
312
|
-
{
|
|
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
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// 2. Server Success Response
|
|
326
|
-
{
|
|
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
|
|
354
|
-
}
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
#### Error Handling with Business Context
|
|
358
|
-
```typescript
|
|
359
|
-
// Business Logic Error
|
|
360
|
-
{
|
|
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
|
|
390
|
-
}
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
#### IoT Telemetry Stream
|
|
394
|
-
```typescript
|
|
395
|
-
// Sensor Data (MQTT → WebSocket bridge)
|
|
396
|
-
{
|
|
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"
|
|
420
|
-
},
|
|
421
|
-
"timestamp": 1640995203000
|
|
422
|
-
}
|
|
423
|
-
```
|
|
424
58
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
#### WebSocket Transport
|
|
428
|
-
- **Sending**: All messages wrapped in MessageEnvelope
|
|
429
|
-
- **Receiving**: Automatic envelope parsing and operation-based routing
|
|
430
|
-
- **Subscriptions**: Client-side filtering by operation field
|
|
431
|
-
- **Correlation**: Built-in request/response correlation via `id` field
|
|
432
|
-
|
|
433
|
-
#### HTTP Transport
|
|
434
|
-
- **Sending**: Complete envelope in POST body
|
|
435
|
-
- **Headers**: Operation and correlation ID in HTTP headers
|
|
436
|
-
- **Error Handling**: Envelope-level errors parsed from response body
|
|
437
|
-
- **Subscriptions**: Warning logged (HTTP doesn't support real-time subscriptions)
|
|
438
|
-
|
|
439
|
-
### Server Implementation Guide
|
|
440
|
-
|
|
441
|
-
To implement a compatible server, ensure your server:
|
|
442
|
-
|
|
443
|
-
1. **Parses MessageEnvelope**: All incoming messages should be parsed as MessageEnvelope
|
|
444
|
-
2. **Routes by Operation**: Use the `operation` field to route messages to appropriate handlers
|
|
445
|
-
3. **Preserves Correlation**: Include the same `id` in response messages for request/response patterns
|
|
446
|
-
4. **Uses Error Format**: Return errors in the envelope `error` field with `code` and `message`
|
|
447
|
-
5. **Includes Timestamps**: Add `timestamp` field for message timing information
|
|
448
|
-
|
|
449
|
-
## 🔄 Rust-AsyncAPI Compatibility
|
|
450
|
-
|
|
451
|
-
This template generates clients that work with AsyncAPI-compliant servers. The message envelope format provides a standard way to handle operation routing and correlation across different server implementations.
|
|
452
|
-
|
|
453
|
-
### Key Compatibility Features
|
|
454
|
-
|
|
455
|
-
- **Operation-Based Routing**: Servers can route messages based on the `operation` field
|
|
456
|
-
- **Request/Response Correlation**: Built-in correlation ID support for async request/response patterns
|
|
457
|
-
- **Standardized Error Format**: Consistent error structure across all operations
|
|
458
|
-
- **Transport Agnostic**: Same envelope format works across WebSocket and HTTP transports
|
|
459
|
-
- **Channel Context**: Optional channel information for debugging and routing
|
|
460
|
-
|
|
461
|
-
## 📚 Usage Examples
|
|
59
|
+
// Type-safe API calls
|
|
60
|
+
await client.connect();
|
|
462
61
|
|
|
463
|
-
|
|
62
|
+
// All methods are fully typed
|
|
63
|
+
const user = await client.createUser({
|
|
64
|
+
name: "John Doe", // TypeScript knows this is required
|
|
65
|
+
email: "john@example.com",
|
|
66
|
+
age: 30 // TypeScript knows this is optional
|
|
67
|
+
});
|
|
464
68
|
|
|
465
|
-
|
|
466
|
-
|
|
69
|
+
// Response is fully typed
|
|
70
|
+
console.log(user.id); // TypeScript provides autocomplete
|
|
71
|
+
console.log(user.createdAt); // TypeScript knows this is a Date
|
|
467
72
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
url: 'ws://localhost:8080',
|
|
472
|
-
reconnect: true,
|
|
473
|
-
auth: {
|
|
474
|
-
token: 'your-jwt-token'
|
|
475
|
-
}
|
|
476
|
-
}
|
|
73
|
+
// Real-time subscriptions
|
|
74
|
+
client.onUserCreated((user) => {
|
|
75
|
+
console.log('New user:', user);
|
|
477
76
|
});
|
|
478
|
-
|
|
479
|
-
await client.connect();
|
|
480
|
-
const response = await client.getUserProfile({ userId: '123' });
|
|
481
|
-
console.log(response);
|
|
482
77
|
```
|
|
483
78
|
|
|
484
|
-
### HTTP
|
|
79
|
+
### HTTP Transport
|
|
485
80
|
|
|
486
81
|
```typescript
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
const client = new MyServiceClient({
|
|
82
|
+
// HTTP client with retry logic
|
|
83
|
+
const client = new MyApiClient({
|
|
490
84
|
transport: 'http',
|
|
491
85
|
http: {
|
|
492
|
-
baseUrl: '
|
|
86
|
+
baseUrl: 'https://api.example.com',
|
|
493
87
|
retry: {
|
|
494
88
|
attempts: 3,
|
|
495
|
-
delay: 1000,
|
|
496
89
|
backoff: 'exponential'
|
|
497
90
|
}
|
|
498
91
|
}
|
|
499
92
|
});
|
|
500
93
|
|
|
501
|
-
await client.
|
|
502
|
-
const response = await client.createUser({ name: 'John', email: 'john@example.com' });
|
|
503
|
-
console.log(response);
|
|
94
|
+
const response = await client.getUser({ userId: '123' });
|
|
504
95
|
```
|
|
505
96
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
The generated client provides full TypeScript type safety:
|
|
509
|
-
|
|
510
|
-
```typescript
|
|
511
|
-
// All request/response types are generated from your AsyncAPI spec
|
|
512
|
-
const response = await client.getUserProfile({
|
|
513
|
-
userId: '123' // TypeScript knows this is required
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
// Response is fully typed
|
|
517
|
-
console.log(response.user.name); // TypeScript provides autocomplete
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
## 🔐 Authentication & Retry Support
|
|
521
|
-
|
|
522
|
-
The generated client includes comprehensive authentication and retry capabilities inspired by the Rust server template.
|
|
523
|
-
|
|
524
|
-
### JWT Authentication
|
|
97
|
+
### Authentication
|
|
525
98
|
|
|
526
99
|
```typescript
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
100
|
+
// JWT Authentication
|
|
101
|
+
const client = new MyApiClient({
|
|
102
|
+
transport: 'websocket',
|
|
103
|
+
websocket: { url: 'wss://api.example.com' },
|
|
530
104
|
auth: {
|
|
531
105
|
jwt: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
|
532
106
|
}
|
|
533
107
|
});
|
|
534
108
|
|
|
535
|
-
//
|
|
536
|
-
const
|
|
537
|
-
```
|
|
538
|
-
|
|
539
|
-
### Basic Authentication
|
|
540
|
-
|
|
541
|
-
```typescript
|
|
542
|
-
const client = new MyServiceClient({
|
|
543
|
-
transport: 'http',
|
|
544
|
-
url: 'https://api.example.com',
|
|
545
|
-
auth: {
|
|
546
|
-
basic: {
|
|
547
|
-
username: 'myuser',
|
|
548
|
-
password: 'mypassword'
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
});
|
|
552
|
-
```
|
|
553
|
-
|
|
554
|
-
### API Key Authentication
|
|
555
|
-
|
|
556
|
-
```typescript
|
|
557
|
-
// API Key in header
|
|
558
|
-
const client = new MyServiceClient({
|
|
109
|
+
// API Key Authentication
|
|
110
|
+
const client = new MyApiClient({
|
|
559
111
|
transport: 'http',
|
|
560
|
-
|
|
112
|
+
http: { baseUrl: 'https://api.example.com' },
|
|
561
113
|
auth: {
|
|
562
|
-
|
|
114
|
+
apiKey: {
|
|
563
115
|
key: 'my-api-key-123',
|
|
564
116
|
location: 'header',
|
|
565
117
|
name: 'X-API-Key'
|
|
566
118
|
}
|
|
567
119
|
}
|
|
568
120
|
});
|
|
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
121
|
```
|
|
583
122
|
|
|
584
|
-
|
|
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
|
-
```
|
|
123
|
+
## Template Configuration
|
|
616
124
|
|
|
617
|
-
|
|
125
|
+
Configure the template with parameters:
|
|
618
126
|
|
|
619
|
-
```
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
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
|
-
});
|
|
127
|
+
```bash
|
|
128
|
+
asyncapi generate fromTemplate asyncapi.yaml @ioka-technologies/asyncapi-ts-client-template \
|
|
129
|
+
-o my-client \
|
|
130
|
+
-p clientName=MyApiClient \
|
|
131
|
+
-p packageName=my-api-client \
|
|
132
|
+
-p packageVersion=1.0.0
|
|
637
133
|
```
|
|
638
134
|
|
|
639
|
-
|
|
135
|
+
| Parameter | Default | Description |
|
|
136
|
+
|-----------|---------|-------------|
|
|
137
|
+
| `clientName` | `"{{info.title}}Client"` | Main client class name |
|
|
138
|
+
| `packageName` | `"{{info.title | kebabCase}}-client"` | NPM package name |
|
|
139
|
+
| `packageVersion` | `"{{info.version}}"` | Package version |
|
|
140
|
+
| `author` | `"AsyncAPI Generator"` | Package author |
|
|
141
|
+
| `transports` | `"websocket,http"` | Supported transport protocols |
|
|
640
142
|
|
|
641
|
-
|
|
143
|
+
## Error Handling
|
|
642
144
|
|
|
643
145
|
```typescript
|
|
644
146
|
import { ConnectionError, MessageTimeoutError, HttpError } from './my-client';
|
|
645
147
|
|
|
646
148
|
try {
|
|
647
|
-
await client.
|
|
149
|
+
await client.createUser(userData);
|
|
648
150
|
} catch (error) {
|
|
649
151
|
if (error instanceof ConnectionError) {
|
|
650
152
|
console.error('Connection failed:', error.message);
|
|
@@ -656,73 +158,49 @@ try {
|
|
|
656
158
|
}
|
|
657
159
|
```
|
|
658
160
|
|
|
659
|
-
##
|
|
660
|
-
|
|
661
|
-
```bash
|
|
662
|
-
# Test the template with the example API
|
|
663
|
-
cd template
|
|
664
|
-
npm install
|
|
665
|
-
node test.js
|
|
666
|
-
```
|
|
667
|
-
|
|
668
|
-
## 🏗️ Generated Project Structure
|
|
669
|
-
|
|
670
|
-
When you generate a client, you'll get a complete TypeScript project:
|
|
161
|
+
## Generated Project Structure
|
|
671
162
|
|
|
672
163
|
```
|
|
673
164
|
my-client/
|
|
674
165
|
├── package.json # NPM package configuration
|
|
675
166
|
├── tsconfig.json # TypeScript configuration
|
|
676
|
-
├── README.md # Generated documentation
|
|
677
|
-
├── USAGE.md # Detailed usage instructions
|
|
678
167
|
├── src/
|
|
679
168
|
│ ├── index.ts # Main exports
|
|
680
169
|
│ ├── client.ts # Generated client class
|
|
681
|
-
│ ├── models.ts #
|
|
682
|
-
│
|
|
683
|
-
│ └── runtime/ # Runtime implementation
|
|
684
|
-
│ ├── types.ts # Core type definitions
|
|
685
|
-
│ ├── errors.ts # Error classes
|
|
686
|
-
│ └── transports/ # Transport implementations
|
|
687
|
-
│ ├── factory.ts # Transport factory
|
|
688
|
-
│ ├── websocket.ts # WebSocket transport
|
|
689
|
-
│ └── http.ts # HTTP transport
|
|
170
|
+
│ ├── models.ts # TypeScript interfaces
|
|
171
|
+
│ └── runtime/ # Transport implementations
|
|
690
172
|
└── examples/ # Usage examples
|
|
691
|
-
├── websocket-example.ts # WebSocket example
|
|
692
|
-
└── http-example.ts # HTTP example
|
|
693
173
|
```
|
|
694
174
|
|
|
695
|
-
##
|
|
175
|
+
## Examples
|
|
696
176
|
|
|
697
|
-
|
|
698
|
-
- **[PROJECT_SUMMARY.md](./PROJECT_SUMMARY.md)** - Complete project summary
|
|
699
|
-
- **[template/README.md](./template/README.md)** - Template-specific documentation
|
|
177
|
+
See the [examples directory](../examples/) for sample AsyncAPI specifications and generated clients.
|
|
700
178
|
|
|
701
|
-
##
|
|
179
|
+
## Development
|
|
702
180
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
5. Submit a pull request
|
|
181
|
+
```bash
|
|
182
|
+
# Clone and test locally
|
|
183
|
+
git clone https://github.com/Ioka-Technologies/asyncapi-template.git
|
|
184
|
+
cd asyncapi-template/ts-client
|
|
708
185
|
|
|
709
|
-
|
|
186
|
+
# Run tests
|
|
187
|
+
npm test
|
|
188
|
+
```
|
|
710
189
|
|
|
711
|
-
|
|
712
|
-
- **TypeScript**: >= 4.5.0
|
|
713
|
-
- **AsyncAPI CLI**: Latest version
|
|
190
|
+
## Contributing
|
|
714
191
|
|
|
715
|
-
|
|
192
|
+
1. Fork the repository
|
|
193
|
+
2. Create a feature branch
|
|
194
|
+
3. Make your changes and add tests
|
|
195
|
+
4. Run the test suite: `npm test`
|
|
196
|
+
5. Submit a pull request
|
|
197
|
+
|
|
198
|
+
## License
|
|
716
199
|
|
|
717
|
-
|
|
200
|
+
Apache-2.0
|
|
718
201
|
|
|
719
|
-
##
|
|
202
|
+
## Related Projects
|
|
720
203
|
|
|
721
204
|
- [AsyncAPI Generator](https://github.com/asyncapi/generator)
|
|
722
205
|
- [AsyncAPI CLI](https://github.com/asyncapi/cli)
|
|
723
|
-
- [Rust
|
|
724
|
-
- [AsyncAPI Specification](https://github.com/asyncapi/spec)
|
|
725
|
-
|
|
726
|
-
---
|
|
727
|
-
|
|
728
|
-
Generated with ❤️ by [AsyncAPI Generator](https://github.com/asyncapi/generator)
|
|
206
|
+
- [Rust Server Template](../rust-server/)
|