add readme
This commit is contained in:
345
README.md
Normal file
345
README.md
Normal file
@@ -0,0 +1,345 @@
|
||||
# NATS Client Module - Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
The `natsClient.js` module provides a comprehensive NATS WebSocket client with automatic reconnection, request/reply messaging, and msghandler integration.
|
||||
|
||||
## Features
|
||||
|
||||
- **Automatic Connection**: Connects to NATS server on demand
|
||||
- **Auto-Reconnection**: Exponential backoff reconnection on connection loss
|
||||
- **Request/Reply**: NATS request/reply pattern for synchronous communication
|
||||
- **Publish/Subscribe**: NATS pub/sub pattern for broadcast messaging
|
||||
- **Msghandler Integration**: Automatic envelope wrapping/unwrapping for message serialization
|
||||
|
||||
## API Reference
|
||||
|
||||
### Connection Management
|
||||
|
||||
#### `getNats(opts)`
|
||||
|
||||
Establishes connection to NATS server.
|
||||
|
||||
```javascript
|
||||
import { getNats } from './natsClient.js';
|
||||
|
||||
// Connect to default server
|
||||
await getNats();
|
||||
|
||||
// Connect to custom server
|
||||
await getNats({ servers: 'wss://nats.yiem.cc' });
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `opts.servers` (string): NATS server URL (default: `wss://nats.yiem.cc`)
|
||||
|
||||
**Returns:** `Promise<nc>` - NATS connection object
|
||||
|
||||
#### `connectNATS(brokerUrl, config)`
|
||||
|
||||
Connects to NATS broker using the provided URL or config.
|
||||
|
||||
```javascript
|
||||
import { connectNATS } from './natsClient.js';
|
||||
|
||||
await connectNATS('wss://nats.yiem.cc');
|
||||
// or
|
||||
await connectNATS(null, { nats_server_info: { url: 'wss://nats.yiem.cc' } });
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `brokerUrl` (string): NATS broker URL
|
||||
- `config` (object): Configuration object with `nats_server_info.url`
|
||||
|
||||
#### `closeNats()`
|
||||
|
||||
Closes the NATS connection and unsubscribes from all topics.
|
||||
|
||||
```javascript
|
||||
import { closeNats } from './natsClient.js';
|
||||
|
||||
await closeNats();
|
||||
```
|
||||
|
||||
### Subscription
|
||||
|
||||
#### `subscribe(subject, onMessage)`
|
||||
|
||||
Subscribes to a NATS subject and registers a message handler.
|
||||
|
||||
```javascript
|
||||
import { subscribe } from './natsClient.js';
|
||||
|
||||
const subscription = await subscribe('sommpanion.backend.dbapi.v1.inbox', (message) => {
|
||||
console.log('Received message:', message);
|
||||
});
|
||||
|
||||
// Later, to unsubscribe:
|
||||
await subscription.unsubscribe();
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `subject` (string): NATS subject to subscribe to
|
||||
- `onMessage` (function): Callback function to handle incoming messages
|
||||
|
||||
**Returns:** `Promise<{unsubscribe: Function}>` - Subscription object with unsubscribe method
|
||||
|
||||
### Publishing
|
||||
|
||||
#### `publish(subject, payload, opts)`
|
||||
|
||||
Publishes a message to a NATS subject.
|
||||
|
||||
```javascript
|
||||
import { publish } from './natsClient.js';
|
||||
|
||||
await publish('sommpanion.backend.dbapi.v1.inbox', { cmd: 'search', data: { keyword: 'chardonnay' } });
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `subject` (string): NATS subject to publish to
|
||||
- `payload` (object|string): Message payload
|
||||
- `opts` (object): Optional configuration
|
||||
|
||||
### Request/Reply
|
||||
|
||||
#### `request(subject, payload, opts)`
|
||||
|
||||
Sends a request and waits for a reply using NATS request/reply pattern.
|
||||
|
||||
```javascript
|
||||
import { request } from './natsClient.js';
|
||||
|
||||
const response = await request(
|
||||
'sommpanion.backend.dbapi.v1.inbox',
|
||||
{ functioncall: 'search_wine_table', args: { searchkeyword: 'chardonnay' } }
|
||||
);
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `subject` (string): NATS subject to send request to
|
||||
- `payload` (string|object): Request payload
|
||||
- `opts` (object): Optional configuration
|
||||
|
||||
**Returns:** `Promise<object>` - Response from the server
|
||||
|
||||
#### `reply(subject, handler, opts)`
|
||||
|
||||
Sets up a reply handler for request/reply pattern.
|
||||
|
||||
```javascript
|
||||
import { reply } from './natsClient.js';
|
||||
|
||||
const subscription = await reply('sommpanion.backend.dbapi.v1.inbox', (request, msg) => {
|
||||
return { functioncall: request.functioncall, result: 'success', type: 'text' };
|
||||
});
|
||||
|
||||
// Later, to unsubscribe:
|
||||
await subscription.unsubscribe();
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `subject` (string): NATS subject to listen on
|
||||
- `handler` (function): Handler function that returns response
|
||||
- `opts` (object): Optional configuration
|
||||
|
||||
**Returns:** `Promise<{unsubscribe: Function}>` - Subscription object with unsubscribe method
|
||||
|
||||
### Msghandler Integration
|
||||
|
||||
#### `sendMsghandlerRequest(subject, functioncall, args, config)`
|
||||
|
||||
Sends a request using msghandler envelope format for proper message serialization.
|
||||
|
||||
```javascript
|
||||
import { sendMsghandlerRequest } from './natsClient.js';
|
||||
import msghandlerCSR from './msghandler-csr.js';
|
||||
|
||||
const response = await sendMsghandlerRequest(
|
||||
'sommpanion.backend.dbapi.v1.inbox',
|
||||
'search_wine_table',
|
||||
{ searchkeyword: 'chardonnay', searchcolumn: 'wine_name' },
|
||||
{ nats_server_info: { url: 'wss://nats.yiem.cc' } }
|
||||
);
|
||||
|
||||
console.log(response.result); // Array of wine records
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `subject` (string): NATS subject to send request to
|
||||
- `functioncall` (string): Backend function to invoke (e.g., `search_wine_table`)
|
||||
- `args` (object): Function arguments
|
||||
- `config` (object): Configuration object containing `nats_server_info.url`
|
||||
|
||||
**Returns:** `Promise<object>` - Response with `functioncall`, `result`, and `type` fields
|
||||
|
||||
### Configuration
|
||||
|
||||
#### Connection Status Store
|
||||
|
||||
```javascript
|
||||
import { connectionStatus } from './natsClient.js';
|
||||
|
||||
connectionStatus.subscribe(status => {
|
||||
console.log('NATS status:', status);
|
||||
});
|
||||
```
|
||||
|
||||
The `connectionStatus` store emits objects with:
|
||||
- `state`: `"connecting"`, `"connected"`, `"error"`, `"disconnected"`
|
||||
- `message`: Human-readable status message
|
||||
|
||||
## End-to-End Examples
|
||||
|
||||
### Example 1: Search with Msghandler
|
||||
|
||||
```javascript
|
||||
import { sendMsghandlerRequest, connectNATS } from './natsClient.js';
|
||||
|
||||
async function searchWines(keyword) {
|
||||
await connectNATS(null, { nats_server_info: { url: 'wss://nats.yiem.cc' } });
|
||||
|
||||
const response = await sendMsghandlerRequest(
|
||||
'sommpanion.backend.dbapi.v1.inbox',
|
||||
'search_wine_table',
|
||||
{
|
||||
searchkeyword: keyword,
|
||||
searchcolumn: 'seo_name'
|
||||
},
|
||||
{ nats_server_info: { url: 'wss://nats.yiem.cc' } }
|
||||
);
|
||||
|
||||
if (response && response.result) {
|
||||
console.log('Found wines:', response.result);
|
||||
return response.result;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2: Complete Search Component Integration
|
||||
|
||||
```javascript
|
||||
import { sendMsghandlerRequest, getNats } from './natsClient.js';
|
||||
|
||||
export async function searchWines(keyword, config) {
|
||||
try {
|
||||
await getNats();
|
||||
|
||||
const searchPayload = {
|
||||
searchkeyword: keyword || '*',
|
||||
searchcolumn: 'seo_name'
|
||||
};
|
||||
|
||||
const response = await sendMsghandlerRequest(
|
||||
config?.dbservice_subject || 'sommpanion.backend.dbapi.v1.inbox',
|
||||
'search_wine_table',
|
||||
searchPayload,
|
||||
config
|
||||
);
|
||||
|
||||
return response?.result || [];
|
||||
|
||||
} catch (error) {
|
||||
console.error('Search failed:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Connection Errors
|
||||
|
||||
```javascript
|
||||
import { connectNATS } from './natsClient.js';
|
||||
|
||||
try {
|
||||
await connectNATS('wss://nats.yiem.cc');
|
||||
} catch (error) {
|
||||
console.error('NATS connection failed:', error);
|
||||
}
|
||||
```
|
||||
|
||||
### Request/Reply Errors
|
||||
|
||||
```javascript
|
||||
import { sendMsghandlerRequest, connectNATS } from './natsClient.js';
|
||||
|
||||
try {
|
||||
const response = await sendMsghandlerRequest(
|
||||
'sommpanion.backend.dbapi.v1.inbox',
|
||||
'search_wine_table',
|
||||
{ searchkeyword: '*', searchcolumn: 'seo_name' },
|
||||
{ nats_server_info: { url: 'wss://nats.yiem.cc' } }
|
||||
);
|
||||
|
||||
console.log(response.result);
|
||||
} catch (error) {
|
||||
console.error('Request failed:', error.message);
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Reuse Connection**: Don't connect/disconnect for each request. Connect once on app startup.
|
||||
2. **Handle Errors**: Always wrap NATS operations in try-catch blocks.
|
||||
3. **Use Msghandler**: Always use `sendMsghandlerRequest()` for backend API calls.
|
||||
4. **Clean Up**: Unsubscribe from topics when components are destroyed.
|
||||
5. **Configuration**: Read NATS server URL from config for environment-specific configuration.
|
||||
|
||||
## Msghandler Message Format
|
||||
|
||||
### Request Envelope
|
||||
|
||||
When using `sendMsghandlerRequest()`, the module automatically:
|
||||
1. Wraps the payload in msghandler format
|
||||
2. Uses `dictionary` payload type with `db_request` data name
|
||||
3. Automatically selects transport based on payload size
|
||||
|
||||
### Response Format
|
||||
|
||||
The response from backend follows this structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"correlation_id": "uuid-v4",
|
||||
"msg_id": "uuid-v4",
|
||||
"timestamp": "2026-05-26T...",
|
||||
"send_to": "sommpanion.backend.dbapi.v1.inbox",
|
||||
"msg_purpose": "chat",
|
||||
"sender_name": "agent-backend",
|
||||
"payloads": [
|
||||
["db_request", {
|
||||
"functioncall": "search_wine_table",
|
||||
"result": [...],
|
||||
"type": "jsontable"
|
||||
}, "dictionary"]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The `sendMsghandlerRequest()` function automatically:
|
||||
- Unwraps the envelope using `smartunpack()`
|
||||
- Extracts the result from `payloads[0][1]`
|
||||
- Returns `{functioncall, result, type}` object
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Issues
|
||||
|
||||
- Verify NATS server URL in config
|
||||
- Check network connectivity
|
||||
- Ensure NATS server is running
|
||||
|
||||
### Request Timeouts
|
||||
|
||||
- Check backend service is running
|
||||
- Verify subject matches backend listener
|
||||
|
||||
### Response Parsing Errors
|
||||
|
||||
- Ensure backend returns msghandler format
|
||||
- Check payload type matches expected format
|
||||
- Verify `functioncall` and `result` fields exist in response
|
||||
Reference in New Issue
Block a user