DEV Community

Jaligama Satyaveer
Jaligama Satyaveer

Posted on

Understanding WebSockets: Real-Time Data Transfer Made Easy

WebSockets are commonly used in applications that require real-time updates and bidirectional communication between the client and server. They are ideal for chat applications, financial dashboards and payment status tracking. In this article, we will explore how WebSockets can be implemented to provide instant payment status updates in a web application.

In traditional systems, the frontend would need to keep checking the payment status through repeated API calls. With WebSockets, the server can emit events as soon as the payment is processed, reducing unnecessary API calls and improving efficiency.

Breaking Down the WebSockets Implementation

Frontend
1. Initializing WebSocket Connection

import { io } from "socket.io-client";

const socket = io(process.env.API_BASE_URL, { autoConnect: false });
Enter fullscreen mode Exit fullscreen mode
  • The frontend initializes a WebSocket connection to the backend using io(process.env.API_BASE_URL, { autoConnect: false }).

  • autoConnect: false ensures that the socket does not connect automatically until explicitly called.

2. Handling Connection and Events

useEffect(() => {
  socket.connect();

  socket.on("socket-id", setSocketId);
  socket.on("payment-status", setPaymentStatus);

  return () => {
    socket.off("socket-id");
    socket.off("payment-status");
    socket.disconnect();
  };
}, []);
Enter fullscreen mode Exit fullscreen mode
  • socket.connect() establishes the connection.

  • Listens for:

    • socket-id: Receives and stores the unique identifier assigned by the server.
    • payment-status: Updates the payment status in real-time.
  • Cleanup:

    • socket.off(...) ensures that event listeners are removed when the component unmounts.
    • socket.disconnect() properly closes the connection.

3. Sending Data to Backend

await axios.post(
  `${process.env.API_BASE_URL}/api/payments/make-payment-with-socket`,
  { amount: 1000, socketId }
);
Enter fullscreen mode Exit fullscreen mode
  • The client sends a payment request to the backend API, including the socketId.

  • This ensures the server knows which client to send the payment status update to.

Backend
1. Setting Up WebSockets (socket.js)

const { Server } = require("socket.io");

let io;

const setupSocket = (server) => {
  io = new Server(server, {
    cors: { origin: "http://localhost:3000" },
  });

  io.on("connection", (socket) => {
    console.log(`User connected: ${socket.id}`);
    socket.emit("socket-id", socket.id);

    socket.on("disconnect", () =>
      console.log(`User disconnected: ${socket.id}`)
    );
  });
};

const emitPaymentStatus = (socketId, status) => {
  if (io) io.to(socketId).emit("payment-status", status);
};

module.exports = { setupSocket, emitPaymentStatus };
Enter fullscreen mode Exit fullscreen mode
  • setupSocket(server): Initializes the WebSocket server.

  • Handles Connections:

    • When a client connects, it assigns a unique socket.id.
    • It sends the socket-id back to the client.
    • It listens for disconnection events.
  • Emitting Events:

    • The emitPaymentStatus function emits the payment-status event to a specific client using their socketId.

2. Integrating WebSockets with Express (index.js)

const express = require("express");
const http = require("http");
const { setupSocket } = require("./socket");

const app = express();
const server = http.createServer(app);
setupSocket(server);

server.listen(PORT, () => {
  console.log(`Backend server running on port ${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode
  • http.createServer(app): Creates an HTTP server to attach WebSockets to.

  • setupSocket(server): Passes the server to the WebSocket setup function.

  • server.listen(PORT): Starts the backend server.

3. Emitting Events After Payment (paymentRoutes.js)

const { emitPaymentStatus } = require("../socket");

router.post("/make-payment-with-socket", (req, res) => {
  const { socketId } = req.body;

  setTimeout(() => {
    emitPaymentStatus(socketId, true);
  }, 10000);

  res.status(200).json({ message: "Payment received, processing request" });
});
Enter fullscreen mode Exit fullscreen mode
  • The backend receives the socketId from the frontend.

  • Simulates payment processing with setTimeout().

  • Calls emitPaymentStatus(socketId, true) to notify the client of a successful payment.

Check Payment status - Without WebSocket

Check Payment status - With WebSocket

Code
Frontend
Backend

Conclusion

WebSockets enable real-time, event-driven communication between the client and server, significantly reducing the need for repeated API polling. This improves efficiency, reduces server load, and enhances user experience. By implementing WebSockets in the payment processing system, we eliminate unnecessary requests and enable instant status updates.

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay