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.
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.
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 URLconfig(object): Configuration object withnats_server_info.url
closeNats()
Closes the NATS connection and unsubscribes from all topics.
import { closeNats } from './natsClient.js';
await closeNats();
Subscription
subscribe(subject, onMessage)
Subscribes to a NATS subject and registers a message handler.
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 toonMessage(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.
import { publish } from './natsClient.js';
await publish('sommpanion.backend.dbapi.v1.inbox', { cmd: 'search', data: { keyword: 'chardonnay' } });
Parameters:
subject(string): NATS subject to publish topayload(object|string): Message payloadopts(object): Optional configuration
Request/Reply
request(subject, payload, opts)
Sends a request and waits for a reply using NATS request/reply pattern.
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 topayload(string|object): Request payloadopts(object): Optional configuration
Returns: Promise<object> - Response from the server
reply(subject, handler, opts)
Sets up a reply handler for request/reply pattern.
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 onhandler(function): Handler function that returns responseopts(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.
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 tofunctioncall(string): Backend function to invoke (e.g.,search_wine_table)args(object): Function argumentsconfig(object): Configuration object containingnats_server_info.url
Returns: Promise<object> - Response with functioncall, result, and type fields
Configuration
Connection Status Store
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
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
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
import { connectNATS } from './natsClient.js';
try {
await connectNATS('wss://nats.yiem.cc');
} catch (error) {
console.error('NATS connection failed:', error);
}
Request/Reply Errors
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
- Reuse Connection: Don't connect/disconnect for each request. Connect once on app startup.
- Handle Errors: Always wrap NATS operations in try-catch blocks.
- Use Msghandler: Always use
sendMsghandlerRequest()for backend API calls. - Clean Up: Unsubscribe from topics when components are destroyed.
- Configuration: Read NATS server URL from config for environment-specific configuration.
Msghandler Message Format
Request Envelope
When using sendMsghandlerRequest(), the module automatically:
- Wraps the payload in msghandler format
- Uses
dictionarypayload type withdb_requestdata name - Automatically selects transport based on payload size
Response Format
The response from backend follows this structure:
{
"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
functioncallandresultfields exist in response