Using the fastify-websocket Library
WebSocket is a protocol enabling full-duplex communication over a single persistent connection, ideal for real-time data pushing, chat applications, gaming servers, and more. Fastify supports WebSocket functionality through the fastify-websocket plugin.
Installing fastify-websocket
Install the fastify-websocket plugin:
npm install fastify-websocketConfiguring WebSocket
Register the fastify-websocket plugin in your Fastify application:
const fastify = require('fastify')();
const fastifyWebsocket = require('fastify-websocket');
fastify.register(fastifyWebsocket);
fastify.listen({ port: 3000 }, (err, address) => {
if (err) throw err;
console.log(`Server listening on ${address}`);
});Creating WebSocket Routes
Once registered, create WebSocket routes using the websocket: true option:
fastify.get('/ws', { websocket: true }, (connection, request) => {
connection.on('message', (message) => {
console.log('received: %s', message.toString());
connection.send(message);
});
});Sending and Receiving Messages
Use connection.send() to send messages to clients, which listen for message events:
// Server sending message
connection.send(JSON.stringify({ text: 'Hello from server!' }));
// Client receiving message
socket.addEventListener('message', function(event) {
console.log('Message from server ', event.data);
});Example: Simple Chat Application
A basic chat application using Fastify and WebSocket:
const fastify = require('fastify')();
const fastifyWebsocket = require('fastify-websocket');
fastify.register(fastifyWebsocket);
let clients = [];
fastify.get('/ws', { websocket: true }, (connection, request) => {
clients.push(connection);
connection.on('message', (message) => {
const data = JSON.parse(message);
console.log('received: %s', data.text);
clients.forEach(client => {
client.send(JSON.stringify(data));
});
});
connection.once('close', () => {
clients = clients.filter(c => c !== connection);
});
});
fastify.listen({ port: 3000 }, (err, address) => {
if (err) throw err;
console.log(`Server listening on ${address}`);
});This broadcasts messages to all connected clients, implementing a simple chat room.
Client Code
Use the browser’s WebSocket object to connect:
<script>
var socket = new WebSocket('ws://localhost:3000/ws');
socket.addEventListener('open', function (event) {
console.log('Connected to server');
});
socket.addEventListener('message', function (event) {
console.log('Message from server ', event.data);
});
socket.send(JSON.stringify({ text: 'Hello from client!' }));
</script>Namespaces and Rooms
Organize connections into rooms or namespaces for applications like chat rooms:
fastify.get('/ws/:room', { websocket: true }, (connection, request) => {
const room = request.params.room;
joinRoom(connection, room);
connection.on('message', (message) => {
broadcastToRoom(room, message);
});
connection.once('close', () => {
leaveRoom(connection, room);
});
});joinRoom, broadcastToRoom, and leaveRoom are custom functions for room management.
Heartbeat Detection
Detect inactive connections with a heartbeat mechanism:
const HEARTBEAT_INTERVAL = 30000;
const TIMEOUT = 10000;
function setupHeartbeat(connection) {
let timeoutId;
const sendHeartbeat = () => {
connection.send('ping');
timeoutId = setTimeout(() => {
connection.close();
}, TIMEOUT);
};
connection.on('message', (message) => {
if (message.toString() === 'pong') {
clearTimeout(timeoutId);
timeoutId = null;
sendHeartbeat();
}
});
sendHeartbeat();
}Error Handling
Handle WebSocket errors for stability:
connection.on('error', (error) => {
console.error('WebSocket error:', error);
});Performance Optimization
For high-concurrency scenarios:
- Buffers: Use
Bufferfor efficient large data transfers. - CPU Usage: Avoid heavy operations in message handlers; use worker threads or task queues.
- Compression: Enable WebSocket compression to reduce data size.
Security
Secure WebSocket connections with authentication:
fastify.get('/ws', { websocket: true }, (connection, request) => {
if (!request.session.user) {
connection.close();
} else {
// Proceed with connection
}
});WebSockets and Socket.IO Integration
Socket.IO is a popular library providing a high-level abstraction over WebSockets, with fallbacks like long-polling when WebSocket is unavailable.
Installing Socket.IO
Install Socket.IO:
npm install socket.ioSetting Up Socket.IO Server
Create a Socket.IO server:
const io = require('socket.io')(3000);
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('chat message', (msg) => {
console.log('message: ' + msg);
io.emit('chat message', msg);
});
socket.on('disconnect', () => {
console.log('user disconnected');
});
});Connecting to Socket.IO Server
Include the Socket.IO client library:
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io('http://localhost:3000');
socket.on('chat message', (msg) => {
console.log('received: ' + msg);
});
socket.emit('chat message', 'hello!');
</script>Advanced Socket.IO Features
- Rooms: Group connections for chat rooms or games.
- Namespaces: Create isolated Socket.IO instances.
- Binary Data: Support for Blob and ArrayBuffer.
- Reconnection: Automatic reconnection on disconnect.
- Compression: Reduce bandwidth usage.
Namespaces and Rooms Usage
Namespaces isolate services:
const ioChat = require('socket.io')(3001, { path: '/chat/socket.io' });
const ioNotifications = require('socket.io')(3002, { path: '/notifications/socket.io' });
ioChat.on('connection', (socket) => {
// Chat events
});
ioNotifications.on('connection', (socket) => {
// Notification events
});Rooms group connections:
socket.on('joinRoom', (roomName) => {
socket.join(roomName);
socket.to(roomName).emit('welcome', 'Welcome to the room!');
});Custom Handshake Authentication
Authenticate during the handshake:
const io = require('socket.io')(3000, {
cors: {
origin: '*',
methods: ['GET', 'POST']
}
});
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (token && validateToken(token)) {
return next();
}
return next(new Error('authentication error'));
});
io.on('connection', (socket) => {
// Authenticated connection
});Error Handling and Monitoring
Monitor Socket.IO events:
socket.on('connect_error', (err) => {
console.error('connect_error due to ' + err.message);
});
socket.on('connect_timeout', () => {
console.error('connect_timeout');
});
socket.on('error', (err) => {
console.error('Socket.IO error: ' + err.message);
});Performance and Load Balancing
Optimize for high concurrency:
- Clustering: Use Node.js
clustermodule. - Load Balancing: Use Nginx for distributing connections.
- Session Persistence: Use Redis for session data.
Socket.IO with Fastify
Combining Fastify’s high-performance framework with Socket.IO enables flexible real-time applications.
Installing Required Modules
Install Fastify and Socket.IO:
npm install fastify @fastify/socket.ioIntegrating Socket.IO with Fastify
Register the fastify-socket.io plugin:
const fastify = require('fastify')();
const fastifySocketIo = require('@fastify/socket.io');
fastify.register(fastifySocketIo, {
cors: {
origin: true,
credentials: true
}
});
fastify.listen({ port: 3000 }, (err, address) => {
if (err) throw err;
console.log(`Server listening on ${address}`);
});Using Socket.IO
Access the Socket.IO instance via fastify.io:
const io = fastify.io;
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('chat message', (msg) => {
io.emit('chat message', msg);
});
socket.on('disconnect', () => {
console.log('user disconnected');
});
});Handling HTTP Requests and WebSocket
Combine HTTP and WebSocket handling:
fastify.get('/', async (request, reply) => {
return { hello: 'world' };
});



