CodingNic

Web APIs and Backend Communication

A First Look at WebSockets

Web APIs and Backend Communication 15 min read

A First Look at WebSockets

Objectives

By the end of this chapter, you should be able to:

  • Explain what a WebSocket is and how it differs from a fetch() request
  • Open a WebSocket connection and send and receive messages
  • Explain when polling with fetch() is enough, and when it isn’t

💡 Why this matters: fetch() is a one-time question and answer, ask, get a response, done. Some things, a chat message arriving, a live score updating, a stock price ticking, need the server to be able to speak first, without the page having to keep asking. That’s what WebSockets are for.

⚠️ A note on verification: WebSockets need a real, live WebSocket server to connect to, this sandbox’s network access doesn’t reach one (the same restriction covered throughout this module). The code below is accurate, based on the standardized WebSocket API, run it yourself against a real WebSocket server (or a public echo-test one) to see it firsthand.

The Problem: fetch() Only Answers When Asked

Every fetch() call (Module 3) follows the same shape: the page asks a question, the server answers, the connection ends. If you want to know about something new happening on the server, a new chat message, for example, fetch() alone can’t tell you, it has no way to speak up on its own.

One common workaround is polling: call fetch() again every few seconds, just to check.

javascript
setInterval(async () => {
  const response = await fetch("https://api.example-chat.com/messages/latest");
  const message = await response.json();
  console.log("Latest message:", message.text);
}, 3000);

This works, but it’s wasteful, most of those requests come back with nothing new, and it’s not truly real-time, a message that arrives right after a poll waits up to 3 seconds to be noticed.

The Alternative: A WebSocket Connection

A WebSocket opens one long-lived connection between the page and the server, and either side can send a message across it, at any time, without the other side asking first.

javascript
const socket = new WebSocket("wss://chat.example-chat.com");

new WebSocket(url) starts the connection. Notice the URL scheme: wss:// (secure WebSocket), the WebSocket equivalent of https://, or ws:// for an insecure connection, the WebSocket equivalent of plain http://.

Listening for Events

A WebSocket object fires events as the connection’s state changes, and whenever a message arrives.

javascript
socket.onopen = () => {
  console.log("Connected!");
};

socket.onmessage = (event) => {
  console.log("Received:", event.data);
};

socket.onclose = () => {
  console.log("Connection closed");
};

socket.onerror = (error) => {
  console.log("Something went wrong:", error);
};

onopen fires once, when the connection is first established. onmessage fires every single time the server sends something, this is the event that replaces repeatedly calling fetch(), the server pushes data whenever it has something new, instead of waiting to be asked. event.data holds whatever was sent, often a JSON string that still needs JSON.parse().

Sending a Message

javascript
socket.send("Hello!");
javascript
socket.send(JSON.stringify({ type: "chat", text: "Hello!" }));

.send() works whenever the connection is open, sending plain text or, more commonly in a real app, a JSON string built the same way a fetch() body is. There’s no response value from .send() itself, whatever the server sends back arrives later, through onmessage, completely separately.

Closing the Connection

javascript
socket.close();

Closing a connection you no longer need (leaving a chat page, for example) is good practice, an open WebSocket stays connected, using server resources, until either side closes it or the connection drops.

When to Reach for a WebSocket

Polling with fetch() is simpler, and genuinely fine for anything that doesn’t need to feel instant, checking for new email every 30 seconds, refreshing a dashboard every minute. A WebSocket is worth the extra complexity specifically when updates need to arrive the moment they happen, and happen often enough that repeated polling would be wasteful or noticeably laggy, chat, live collaboration, real-time multiplayer state, live prices.

Try It

These can’t run in this course’s tooling, write the code and, if you have a moment, try it against a public WebSocket echo-test server.

  1. Open a WebSocket connection and log a message from onopen once it connects.
  2. Add an onmessage handler that parses event.data as JSON and logs a specific field from it.
  3. Send a message with .send() after the connection opens, and call .close() five seconds later using setTimeout() (Module 3).
  4. Explain, in your own words, why a stock ticker showing live prices is a good fit for a WebSocket, while a page that shows “how many people have signed up so far” (updated once a day) is not.

Recap

  • fetch() is one question, one answer, then the connection ends. Polling with setInterval() and repeated fetch() calls can simulate “live” updates, but wastefully and with a delay.
  • new WebSocket(url) opens a persistent, two-way connection, either side can send a message at any time.
  • onopen, onmessage, onclose, and onerror handle the connection’s lifecycle, onmessage is the one that replaces repeated polling, .send() sends a message to the server.
  • Reach for a WebSocket when updates need to feel instant and happen often, plain fetch() (with or without polling) is enough for almost everything else.

Next lesson: this module’s exercises, practicing REST conventions, HTTP methods, authentication, and CRUD together.