📦 Installation
Install the Socket.IO client library:
// NPM npm install socket.io-client // Yarn yarn add socket.io-client
🔌 Connection
Connect to the BuyTrade chat backend via the API Gateway.
Gateway WS URL:
https://api.buytrade.app with path=/chat/socket.io
// JavaScript/TypeScript Example
import { io } from 'socket.io-client';
// Connect via API Gateway
const socket = io('https://api.buytrade.app', {
auth: { token: 'your-jwt-token' },
path: '/chat/socket.io',
transports: ['websocket'],
reconnection: true,
reconnectionDelay: 1000,
reconnectionAttempts: 5
});
socket.on('connect', () => {
console.log('Connected to chat server');
console.log('Socket ID:', socket.id);
});
socket.on('disconnect', (reason) => {
console.log('Disconnected:', reason);
});
socket.on('connect_error', (error) => {
console.error('Connection error:', error.message);
});
🔐 Authentication
Authenticate using a JWT token in the connection options. The token must include userId, role, and a valid iss (issuer).
// Pass token during connection
const token = localStorage.getItem('accessToken'); // issued by API Gateway
const socket = io('https://api.buytrade.app/chat', {
auth: { token },
path: '/chat/socket.io',
transports: ['websocket']
});
// Token payload requirements:
// {
// userId: '...',
// role: 'admin' | 'provider' | 'moderator' | 'member' | 'subscriber',
// iss: 'buytrade-auth', // recommended; server enforces secret + claims
// exp:
// }
📤 Rooms & Messaging
Use rooms to group participants. Room names are unique; you can join by name or by the ObjectId returned from create-room.
// Create a room (admin/provider only)
socket.emit('create-room', 'traders-room', (ack) => {
// ack: { ok, roomId?, error? }
console.log('create-room =>', ack);
});
// Join a room (by name or ObjectId)
socket.emit('join-room', 'traders-room', (ack) => {
// ack: { ok, roomId, size }
console.log('join-room =>', ack);
});
// Leave a room
socket.emit('leave-room', 'traders-room', (ack) => {
console.log('leave-room =>', ack);
});
// Typing indicator (ephemeral; TTL 5s in Redis)
socket.emit('typing', { roomId: 'traders-room', isTyping: true });
// Send message to a room (server resolves name to id)
socket.emit('send-message', { roomId: 'traders-room', message: 'Hello everyone!' }, (ack) => {
// ack: { ok, id, roomId }
console.log('send-message ack =>', ack);
});
📥 Receiving Events
Listen for room messages, presence, typing, and receipts:
// New room message
socket.on('new-message', (msg) => {
// { id, roomId, sender, message, timestamp }
console.log('new-message', msg);
});
// Delivery + Read receipts
socket.on('delivery', (d) => console.log('delivery', d));
socket.on('read', (r) => console.log('read', r));
// Typing indicator
socket.on('typing', (t) => console.log('typing', t));
// Presence updates
socket.on('presence:join', (p) => console.log('presence:join', p));
socket.on('presence:leave', (p) => console.log('presence:leave', p));
socket.on('presence:offline', (p) => console.log('presence:offline', p));
// System notices (via Redis Pub/Sub)
socket.on('system:notice', (n) => console.log('system:notice', n));
📋 Event Reference
Client → Server Events
| Event | Payload | Description |
|---|---|---|
create-room |
roomName | Create room (admin/provider only). Ack: { ok, roomId?, error? } |
join-room |
roomIdOrName | Join room by name or ObjectId. Ack: { ok, roomId, size } |
leave-room |
roomId | Leave room. Ack: { ok, size } |
typing |
{ roomId, isTyping } | Typing indicator in a room |
send-message |
{ roomId (name or id), message } | Send room message. Ack: { ok, id, roomId } |
message-read |
{ roomId, id } | Mark message read |
Server → Client Events
| Event | Payload | Description |
|---|---|---|
new-message |
{ id, roomId, sender, message, timestamp } | Receive new room message |
delivery |
{ id, roomId, sender, status } | Delivery receipt (delivered) |
read |
{ id, roomId, reader, timestamp } | Read receipt |
typing |
{ userId, roomId, isTyping } | Typing status in room |
presence:join |
{ userId, roomId, size } | User joined room |
presence:leave |
{ userId, roomId, size } | User left room |
presence:offline |
{ userId, roomId } | User went offline |
system:notice |
{ text, ts } | System broadcast via Pub/Sub |
⚠️ Error Handling
// Handle connection errors
socket.on('connect_error', (error) => {
console.error('Connection failed:', error.message);
// Show user-friendly error message
});
// Handle general errors
socket.on('error', (error) => {
console.error('Socket error:', error);
handleError(error);
});
// Handle disconnection
socket.on('disconnect', (reason) => {
if (reason === 'io server disconnect') {
// Server disconnected, reconnect manually
socket.connect();
}
// Otherwise, socket will auto-reconnect
});
🔄 React/Next.js Example
import { useEffect, useState } from 'react';
import { io } from 'socket.io-client';
function ChatComponent() {
const [socket, setSocket] = useState(null);
const [messages, setMessages] = useState([]);
useEffect(() => {
const newSocket = io('https://api.buytrade.app/chat', {
auth: { token: localStorage.getItem('accessToken') },
path: '/chat/socket.io',
transports: ['websocket']
});
newSocket.on('connect', () => console.log('Connected'));
newSocket.on('new-message', (m) => setMessages(prev => [...prev, m]));
setSocket(newSocket);
return () => newSocket.close();
}, []);
const sendMessage = (roomId, content) => {
socket?.emit('send-message', { roomId, message: content }, (ack) => {
console.log('send-message ack', ack);
});
};
return (
// Your chat UI
null
);
}
📱 React Native Example
import { useEffect, useState } from 'react';
import io from 'socket.io-client';
const ChatScreen = () => {
const [socket, setSocket] = useState(null);
useEffect(() => {
(async () => {
const token = await AsyncStorage.getItem('accessToken');
const newSocket = io('https://api.buytrade.app/chat', {
auth: { token },
path: '/chat/socket.io',
transports: ['websocket']
});
newSocket.on('new-message', (message) => {
// Handle new room message
});
setSocket(newSocket);
})();
return () => socket?.close();
}, []);
// Rest of your component
};