Socket.IO Integration
This guide describes how to use the real-time functionality in BAASIX using Socket.IO integration.
Table of Contents
- Overview
- Configuration
- Available Events
- Client Integration
- Authentication
- Custom Events
- Room Management
- Client Examples
Overview
BAASIX provides real-time functionality through Socket.IO integration, allowing you to implement features like live updates, notifications, chat functionality, and collaborative editing.
Configuration
Socket.IO integration is optional and can be enabled through environment variables:
# Enable Socket.IO functionality
SOCKET_ENABLED=true
# Optional: Configure Socket.IO path (default in this repo: /realtime)
SOCKET_PATH=/realtime
# Optional: CORS origins for Socket.IO (comma-separated)
SOCKET_CORS_ENABLED_ORIGINS=https://yourdomain.com,https://app.yourdomain.com
# Redis configuration for Socket.IO clustering (optional)
CACHE_REDIS_URL=redis://localhost:6379Redis Adapter for Scaling
BAASIX automatically configures Redis adapter for Socket.IO when Redis is available, enabling horizontal scaling across multiple server instances:
// Automatic Redis adapter configuration
if (process.env.CACHE_REDIS_URL) {
const redisAdapter = createAdapter(redisPublisher, redisSubscriber);
io.adapter(redisAdapter);
}Available Events
When Socket.IO is enabled, BAASIX emits events for various system actions:
Item Events
item.created: Emitted when an item is createditem.updated: Emitted when an item is updateditem.deleted: Emitted when an item is deleted
Notification Events
notification.new: Emitted when a new notification is sent to a usernotification.seen: Emitted when a notification is marked as seennotification.deleted: Emitted when a notification is deleted
Authentication Events
user.connected: Emitted when a user connects to Socket.IOuser.disconnected: Emitted when a user disconnects
Event payload structure:
// Item events
{
collection: 'collection_name',
item: {
id: 'item-id',
// ... item data
},
userId: 'user-id',
timestamp: '2025-01-15T10:30:00.000Z'
}
// Notification events
{
notification: {
id: 'notification-id',
type: 'info',
title: 'Notification Title',
message: 'Notification message',
data: { /* additional data */ },
seen: false,
userId: 'user-id',
createdAt: '2025-01-15T10:30:00.000Z'
}
}File Events
file.uploaded: When a file is uploadedfile.deleted: When a file is deleted
Event payload structure:
{
file: {
id: 'file_id',
filename: 'example.jpg',
size: 1024,
mimetype: 'image/jpeg'
},
action: 'uploaded|deleted',
user: 'user_id'
}Custom Events
- Custom events can be emitted from hooks or extensions
Client Integration
Connecting to Socket
import { io } from 'socket.io-client';
const socket = io('http://your-api-domain', {
path: '/realtime', // Match your server configuration (SOCKET_PATH)
transports: ['websocket', 'polling'],
autoConnect: true
});
// Handle connection
socket.on('connect', () => {
console.log('Connected to BAASIX socket server');
});
// Handle disconnection
socket.on('disconnect', () => {
console.log('Disconnected from BAASIX socket server');
});
// Handle errors
socket.on('connect_error', (err) => {
console.error('Socket connection error:', err.message);
});Subscribing to Events
// Listen for item events in a specific collection
socket.on('item.created', (data) => {
if (data.collection === 'posts') {
console.log('New post created:', data.item);
// Update UI with new post
}
});
// Listen for updates to a specific item
socket.on('item.updated', (data) => {
if (data.collection === 'posts' && data.item.id === currentPostId) {
console.log('Current post updated:', data.item);
// Update UI with changes
}
});Authentication
To authenticate socket connections, include the BAASIX authentication token:
import { io } from 'socket.io-client';
// Get the token from your authentication flow
const token = localStorage.getItem('auth_token');
const socket = io('http://your-api-domain', {
path: '/realtime',
auth: {
token: token
}
});Custom Events
You can emit custom events from hooks:
// In a hook file
export default {
id: 'notification-hook',
events: [
{
collection: 'notifications',
action: 'items.create.after',
handler: async (data, context) => {
// Get the socket service from context
const { socket } = context.services;
// Emit to specific user
socket.emitToUser(data.user_id, 'notification.new', {
id: data.id,
message: data.message,
type: data.type
});
return data;
}
}
]
};Room Management
BAASIX automatically manages rooms for authenticated users and collections:
- User-specific room:
user:{userId} - Collection room:
collection:{collectionName} - Item-specific room:
item:{collectionName}:{itemId}
Users are automatically joined to their user-specific room on authentication.
Joining Custom Rooms
Client can request to join custom rooms:
// Join a specific discussion room
socket.emit('join', 'discussion:123', (response) => {
if (response.success) {
console.log('Joined discussion room');
} else {
console.error('Failed to join room:', response.message);
}
});Client Examples
Vanilla JavaScript
const socket = io('http://your-api-domain', {
path: '/realtime',
auth: { token: 'your-auth-token' }
});
// Listen for real-time updates
socket.on('item.created', handleNewItem);
socket.on('item.updated', handleItemUpdate);
function handleNewItem(data) {
if (data.collection === 'messages') {
const messagesList = document.getElementById('messages');
const messageItem = document.createElement('li');
messageItem.textContent = `${data.item.user}: ${data.item.text}`;
messagesList.appendChild(messageItem);
}
}React Integration
import React, { useEffect, useState } from 'react';
import { io } from 'socket.io-client';
const LiveFeed = () => {
const [messages, setMessages] = useState([]);
const [socket, setSocket] = useState(null);
useEffect(() => {
// Get token from your auth context/store
const token = localStorage.getItem('auth_token');
// Initialize socket
const newSocket = io('http://your-api-domain', {
path: '/realtime',
auth: { token }
});
newSocket.on('connect', () => {
console.log('Socket connected');
});
newSocket.on('item.created', (data) => {
if (data.collection === 'messages') {
setMessages(prev => [...prev, data.item]);
}
});
setSocket(newSocket);
// Cleanup on unmount
return () => {
newSocket.disconnect();
};
}, []);
return (
<div className="live-feed">
<h2>Live Messages</h2>
<ul>
{messages.map(msg => (
<li key={msg.id}>{msg.text}</li>
))}
</ul>
</div>
);
};
export default LiveFeed;Vue.js Integration
import { io } from 'socket.io-client';
export default {
data() {
return {
socket: null,
messages: []
};
},
created() {
this.initializeSocket();
},
methods: {
initializeSocket() {
const token = localStorage.getItem('auth_token');
this.socket = io('http://your-api-domain', {
path: '/realtime',
auth: { token }
});
this.socket.on('connect', () => {
console.log('Socket connected');
});
this.socket.on('item.created', (data) => {
if (data.collection === 'messages') {
this.messages.push(data.item);
}
});
}
},
beforeUnmount() {
if (this.socket) {
this.socket.disconnect();
}
},
template: `
<div class="live-feed">
<h2>Live Messages</h2>
<ul>
<li v-for="msg in messages" :key="msg.id">{{ msg.text }}</li>
</ul>
</div>
`
};Related Documentation
- Additional Features - Email templates, storage services, and more
- Item Routes - Working with data in collections
- API Routes Reference - Complete list of all API endpoints