Lesson 09-WebSocket Applications in Modern Frameworks

WebSocket is widely used in modern web development frameworks, providing robust support for real-time communication, instant messaging, online collaboration, gaming, financial trading, and more.

React/Angular/Vue.js (Frontend Frameworks)

In frontend frameworks, WebSocket is often integrated with state management libraries (e.g., Redux, Vuex) to efficiently manage application state and real-time data streams.

React: You can use the native WebSocket API or third-party libraries like socket.io-client to establish WebSocket connections. React lifecycle methods or Hooks (e.g., useEffect) can manage connection setup and teardown.

import { useEffect, useState } from 'react';
import io from 'socket.io-client';

function ChatRoom() {
    const [socket, setSocket] = useState(null);

    useEffect(() => {
        const newSocket = io('https://your-websocket-server.com');
        newSocket.on('message', (msg) => {
            console.log('Received:', msg);
        });
        setSocket(newSocket);

        return () => {
            newSocket.disconnect();
        };
    }, []);

    const sendMessage = (msg) => {
        if (socket) socket.emit('message', msg);
    };

    // ...
}

Angular: RxJS simplifies handling WebSocket event streams. A WebSocket service can encapsulate connection logic for reuse.

import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import * as io from 'socket.io-client';

@Injectable({
    providedIn: 'root'
})
export class WebSocketService {
    private socket;
    private messages$ = new Subject<any>();

    constructor() {
        this.socket = io('https://your-websocket-server.com');
        this.socket.on('message', (msg) => {
            this.messages$.next(msg);
        });
    }

    getMessages(): Observable<any> {
        return this.messages$.asObservable();
    }

    sendMessage(msg: any): void {
        this.socket.emit('message', msg);
    }
}

Vue.js: In Vue, WebSocket logic can be encapsulated using custom plugins or mixins for component reuse.

// WebSocket Plugin
export default {
    install(Vue, options) {
        Vue.prototype.$socket = io(options.url);

        Vue.mixin({
            beforeDestroy() {
                if (this.$socket) {
                    this.$socket.disconnect();
                }
            }
        });
    }
}

Node.js Backend Frameworks (e.g., Express, Koa)

Express: Common approaches involve using libraries like ws or socket.io to handle WebSocket connections. socket.io offers additional features like automatic heartbeats, cross-origin support, and reconnection.

const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const app = express();

const server = http.createServer(app);
const wss = new WebSocket.Server({ server });

wss.on('connection', (ws) => {
    ws.on('message', (message) => {
        console.log('Received:', message);
        wss.clients.forEach(client => {
            if (client.readyState === WebSocket.OPEN) {
                client.send(message);
            }
        });
    });
});

app.use(express.static('public'));

server.listen(3000, () => {
    console.log('Server is running on port 3000');
});

Koa: Koa does not natively support WebSocket but can integrate with Node.js WebSocket libraries or middleware like koa-websocket.

const Koa = require('koa');
const WebSocket = require('ws');
const app = new Koa();
const server = require('http').createServer(app.callback());
const wss = new WebSocket.Server({ server });

wss.on('connection', (ws) => {
    // Handle WebSocket connection logic...
});

app.use(async ctx => {
    // Handle HTTP requests...
});

server.listen(3000, () => {
    console.log('Server is running on port 3000');
});

Python Frameworks (e.g., Django, Flask)

Flask: Flask can implement WebSocket functionality using libraries like Flask-SocketIO, which leverages gevent or eventlet for non-blocking I/O, supporting WebSocket and long polling.

from flask import Flask, render_template
from flask_socketio import SocketIO, emit

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)

@socketio.on('message')
def handle_message(data):
    print('received message: ' + data)
    emit('response', 'This is a response')

@app.route('/')
def index():
    return render_template('index.html')

if __name__ == '__main__':
    socketio.run(app)

Spring Boot (Java)

Spring Boot provides WebSocket support through the Spring WebSocket module, making it straightforward to implement WebSocket functionality in Java applications.

Basic Example:

First, add the Spring WebSocket dependency to pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

Next, define a WebSocket configuration class:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/websocket").withSockJS();
    }
}

Then, create a message handler to process client messages:

@Controller
public class GreetingController {

    @MessageMapping("/hello")
    @SendTo("/topic/greetings")
    public Greeting greeting(HelloMessage message) throws Exception {
        Thread.sleep(1000); // Simulate delay
        return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");
    }
}

Clients (HTML pages or JavaScript applications) can use libraries like Stomp.js or SockJS to connect to the WebSocket service and send/receive messages.

Django Channels (Python)

Django Channels is an extension of Django that allows handling HTTP, WebSocket, and other request types at the same level. It is particularly well-suited for building real-time applications and WebSocket-based systems.

Configuring Channels:

First, ensure channels and daphne (an ASGI-compatible server) are installed:

pip install channels daphne

Add Channels configuration to settings.py:

INSTALLED_APPS = [
    # ...
    'channels',
]

ASGI_APPLICATION = 'myproject.routing.application'

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('127.0.0.1', 6379)],
        },
    },
}

Create a routing file to define WebSocket routes:

# myproject/routing.py
from channels.routing import ProtocolTypeRouter, URLRouter
from django.urls import path
from .consumers import MyConsumer

application = ProtocolTypeRouter({
    "websocket": URLRouter([
        path("ws/myconsumer/", MyConsumer.as_asgi()),
    ]),
})

Write a consumer to handle WebSocket connections:

# myproject/consumers.py
from channels.generic.websocket import AsyncWebsocketConsumer

class MyConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        await self.accept()

    async def disconnect(self, close_code):
        pass

    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        await self.send(text_data=json.dumps({
            'message': message
        }))

Next.js (Frontend Framework)

While Next.js does not directly support WebSocket, you can freely use WebSocket in Next.js applications. Typically, you initialize WebSocket connections in page components or API routes.

Example:

Using WebSocket in a Next.js page component:

import { useEffect, useState } from 'react';

function ChatPage() {
    const [socket, setSocket] = useState(null);
    const [messages, setMessages] = useState([]);

    useEffect(() => {
        const newSocket = new WebSocket('wss://your-websocket-server.com');
        newSocket.onmessage = (event) => {
            setMessages(prev => [...prev, event.data]);
        };
        setSocket(newSocket);

        return () => {
            newSocket.close();
        };
    }, []);

    const sendMessage = (msg) => {
        if (socket && socket.readyState === WebSocket.OPEN) {
            socket.send(msg);
        }
    };

    // ...
}

Nest.js (Node.js Backend Framework)

Nest.js is a progressive Node.js framework that leverages TypeScript’s capabilities and integrates tightly with mature Node.js servers like Express and Fastify. Nest.js supports WebSocket through the official @nestjs/websockets module.

Setting Up the WebSocket Module:

First, install the @nestjs/websockets package:

npm install @nestjs/websockets

Then, configure the WebSocket module in your Nest.js application:

// app.module.ts
import { Module } from '@nestjs/common';
import { WsModule } from '@nestjs/websockets';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { WebSocketGateway } from './web-socket.gateway';

@Module({
  imports: [
    WsModule.forRoot({ transports: ['websocket'] }), // Configure WebSocket module
  ],
  controllers: [AppController],
  providers: [AppService, WebSocketGateway],
})
export class AppModule {}

Creating a WebSocket Gateway:

In Nest.js, WebSocket logic is typically handled in “gateways.”

// web-socket.gateway.ts
import { WebSocketGateway, OnGatewayConnection, OnGatewayDisconnect } from '@nestjs/websockets';

@WebSocketGateway(3001, { namespace: 'chat' }) // Bind to port 3001, namespace 'chat'
export class WebSocketGateway implements OnGatewayConnection, OnGatewayDisconnect {
  @WebSocketServer() server;

  handleConnection(client: any, ...args: any[]) {
    console.log(`Client connected: ${client.id}`);
  }

  handleDisconnect(client: any) {
    console.log(`Client disconnected: ${client.id}`);
  }

  @SubscribeMessage('msgToServer')
  handleMessage(client: any, payload: string): any {
    console.log(`Message received: ${payload}`);
    this.server.emit('msgToClient', `You said: "${payload}"`);
  }
}

In this example, a WebSocket gateway listens for the msgToServer event and broadcasts a response to all clients upon receiving a message.

Quasar (Vue.js Framework)

Quasar is a comprehensive Vue.js-based framework for rapidly building responsive websites, PWAs, SSR apps, mobile apps, and desktop apps. While Quasar does not natively provide WebSocket functionality, integrating WebSocket into Quasar applications is straightforward.

Integrating a WebSocket Client:

Assume you’re using socket.io-client as the WebSocket client library:

Install socket.io-client:

npm install socket.io-client

Use WebSocket in a Quasar Vue component or service:

<template>
  <!-- Template code omitted -->
</template>

<script>
import io from 'socket.io-client';

export default {
  data() {
    return {
      socket: null,
    };
  },
  mounted() {
    this.socket = io('https://your-websocket-server.com');
    this.socket.on('connect', () => {
      console.log('Connected to WebSocket server');
    });
    this.socket.on('message', (msg) => {
      console.log('Received:', msg);
    });
  },
  beforeDestroy() {
    if (this.socket) {
      this.socket.disconnect();
    }
  },
  methods: {
    sendMessage(msg) {
      if (this.socket) {
        this.socket.emit('message', msg);
      }
    },
  },
};
</script>
Share your love