DEV Community

Cover image for Server-Sent Events: A Lightweight Alternative to WebSockets
Husain Sayyed
Husain Sayyed

Posted on

Server-Sent Events: A Lightweight Alternative to WebSockets

I am going to write a few Blogs on Backend Communication Patterns, While this being my first one.

As a Developer, I am sure that one of the most use backend communication patterns is HTTP request. we use them all the time when we need the data from the server.

But with HTTP request calls you can only get data if you ask for it, means that once you request for any data, the server returns the response and close the connection.

Now What if you need the data continuously, like a live match score update. What will you do here ? I am sure most people would say WebSockets.

The problem with WebSockets is that it’s Bi-Directional Communication Protocol, indeed it has it use cases like Chat Applications, but not every use case needs Bi-Directional Communication, What if we only need Server to sent us real time Data ?

Here, is the perfect scenario to use Server Sent Events.

So, What is Server Sent Events ?
Server Sent Events (SSE) is communication done over HTTP protocol. It allows the server to send data to the client once an initial connection has been established.

Connection Flow For SSE

How do you Setup and Work with Server Sent Events ?

As with any normal HTTP request, SSE connection must also initiated by Client ( Browser ). There are few configuration you must do on the Server as well as for Client side code.

Your 1st step would be to set the right Headers in HTTP request.

  1. Set Content-Type header to text/event-stream.
  2. Set Cache-Control header to no-cache.
  3. Connection header to keep-alive.

Example of Request and Response Headers.

While most of the frameworks do this by Default, but it’s nice to know how it is different from normal HTTP requests.

Your 1st step would be to return each data from the backend in the following format :

  1. event — A string specifying the type of data, by default the value is message and you can listen on the eventSource.onmessage . If you decided to use any custom string, then you can listen on that event using addEventListener("MyCustomEvent", (event) => {}).

  2. data — Pass your own custom data, can be anything, String or JSON encoded Object.

  3. id — Create a unique Id from the backend, Maybe a incremental value.

Streaming the event data.

Let’s Dive into Implementation part, I will be using Spring Boot for Backend Server and Angular for the FrontEnd.

I am using Spring Boot since that is what I am familiar with, But you find the setup easily in your programming language. You can refer to the implementation in PHP here.

// using Fiegn Client for https://random-data-api.com/api/v2/
private final RandomUserFiegnClient randomUserFiegnClient;

@GetMapping(path = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> streamEvents() {
    return Flux.interval(Duration.ofSeconds(3))
           .publishOn(Schedulers.boundedElastic())
           .handle((sequence, sink) -> sink.next(ServerSentEvent.<String>builder()
                .id(String.valueOf(sequence))
                .event("message")
                .data(randomUserFiegnClient.getRandomUser().toString())
                .build()));
}
Enter fullscreen mode Exit fullscreen mode

Let’s understand a main parts here,

  1. produces = MediaType.TEXT_EVENT_STREAM_VALUE Basically set the Content-Type header to text/event-stream.

  2. Flux.interval(Duration.ofSeconds(3)) for every 3 seconds send the latest data back to client.

  3. data(randomUserFiegnClient.getRandomUser().toString()) use random data API to return Random User information.

Once this is setup, let’s setup Client side code as well.

// Create an Event Source Object.
// The server-sent event API is contained in the EventSource interface.
const eventSource = new EventSource('http://localhost:8080/sse');

// Once created, Listen on OnOpen Event.
// This will let you if connection to backend is established or Not.
eventSource.onopen = (e) => {
  console.log("The connection has been established.");
  // Add Your Business Logic Here.
  eventSource.onmessage = (event) => {
    console.log(event.lastEventId); // unique event id from the server.
    console.log(event.type); // type of event
    console.log(event.data); // actual Data.
  };
};
Enter fullscreen mode Exit fullscreen mode

The above code is a basic setup, Of course based on your use case you have to modified it a lot. Let’s See how you can check for Connection Errors or Closed the connection if you are done.

eventSource.onerror = (err) => {
  // Maybe display a generic error message, and helpful for developer to debug.
  console.error("EventSource failed:", err);
};

// Let's say you are now done, and You want to close the connection.
eventSource.close();
Enter fullscreen mode Exit fullscreen mode

Make sure you are closing the connection, to prevent overload on servers.
Let’s see the final Implementation :

Implementation of Server Sent Events.

And now for the closing remarks, when you should use Server Sent Events (SSE) for 1-way data streaming.

  1. Live Match Score Updates, Notifications, or Dashboards.
  2. Tracking System.
  3. Or If you just want the server to sent you the real-time data, and there will no communication from the client side.

One Last point, remember it’s Limitation :

  1. Number of Connections — If you are not using HTTP/2, then the maximum connection you can setup is 6. For Chrome check the issue here and firefox here.
  2. Data Format — You can only send UTF-8 messages, unfortunately Binary Data is not supported.

Have you implemented Server-Sent Events in your projects? Or do you have thoughts on real-time communication patterns? Share your experiences, questions, or feedback in the comments below. Let’s continue the conversation and learn from each other’s journeys!

Stay tuned as we dive into more backend communication strategies, uncovering the strengths and nuances of each to help you make informed choices for your applications.

Top comments (0)