WebSockets, gRPC, MQTT, and SSE - Which Real-Time Notification Method Is For You?
Tags: tech, eventdriven, websockets, postman
Published: 2023-10-18 12:04:30


I've been spending quite a bit of time lately exploring the world of real-time notifications. Naively, I was under the impression that real-time communication meant one thing: WebSockets.

More specifically, I thought the term for server to browser communication was "WebSocket." I thought this for years! I even [wrote a 5-part series on WebSockets](https://dev.to/aws-builders/intro-to-aws-websockets-306p) on the subject thinking that's what the term meant (it's a good series, I actually do recommend it).

It wasn't until I started researching the protocol [as part of my day job](https://www.gomomento.com/blog/why-are-websockets-so-hard) that I realized I was wrong. Like, *way wrong*. There are several ways to get data from a server to a browser outside of WebSockets.

Today we're going to cover four of the most popular stateful mechanisms: **WebSockets**, **gRPC**, **MQTT**, and **Server-Sent Events (SSE)**. Each of these is unique in the way they facilitate server to client messages, with pros and cons to consider before you implement a solution.

[![Chart summarizing all the components of real-time notification methods](https://readysetcloud.s3.amazonaws.com/notification_protocols_1.png)](https://readysetcloud.s3.amazonaws.com/notification_protocols_1.png)

## Notification Methods

As I mentioned earlier, there is a long list of notification methods but we'll focus on the four most popular ones. I mentioned they were *stateful*, and it's worth describing what that means.

> A stateful connection is a persistent connection between two entities that remembers previous interactions. As long as the connection is up, the two entities can communicate freely back and forth with each other, much like being on a phone call. When one side hangs up, the connection is terminated, and they can no longer communicate with each other.

Compare this to a stateless communication mechanism like [Amazon SNS](https://aws.amazon.com/sns/) or other [Webhook implementation](https://dev.to/aws-builders/webhooks-explained-simply-with-car-shopping-2jhk) where the connection is not persistent and the communication is one-way. These are intended to be used as a response to an event and inform subscribers without maintaining a continuous connection or keeping memory of previous interactions.

Back to our notification methods:

* **WebSockets** - Bidirectional communication over a single TCP connections. Messages are asynchronous and can be sent from client to server and server to client at the same time. This is natively supported by most browsers.
* **gRPC** - High-performance bidirectional streaming. This not only supports simultaneous client/server and server/client messages like WebSockets, but it also offers multi-plexing, which means multiple messages can be sent in a single direction at the same time without blocking.
* **MQTT** - Minimalistic publish/subscribe communication protocol. Designed for IoT use cases, MQTT offers multiple levels of delivery fidelity (Quality of Service) and defines what to do when a connection is dropped (Last Will and Testament).
* **Server-Sent Events (SSE)** - Simple, one-way communication from a server to a client over HTTP. Mostly intended for browser-based interactions, this mechanism offers features like automatic reconnection and native browser support.

## Use Cases

Now that we know what each of these are, we should talk about when to use them. As with any question in software, the answer of course is *it depends*, but as a general guideline, let's take a look at certain situations where each one is the most appropriate.

* **WebSockets** - Online multiplayer games, chat apps, collaborative tools, etc... Use cases are generally around syncing state between multiple users.
* **gRPC** - Microservice communication, mobile apps, and high-performance systems. Typically you see use cases with requirements around low-latency and efficient bandwith usage.
* **MQTT** - IoT devices. This is generally seen in environments where connections are intermittent and clients are devices that send frequent data.
* **Server-Sent Events** - Live news, sports scoring, monitoring dashboards. Use cases are around getting data from a server with no communication from the client.

Of course you can use these communication mechanisms for other use cases, but generally you will find them best suited for the tasks mentioned above.

## Implementation

We all know I'm an AWS guy, so when AWS has a managed service for something I will typically use it (well, at least try it out for posterity). Below are your options if you're looking to implement one of these communication mechanisms in AWS.

* **WebSockets** - [Amazon API Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-overview.html) and [AWS AppSync subscriptions](https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-data.html). A popular non-AWS option is [Socket.IO](https://socket.io/).
* **gRPC** - AWS does not provide a native service for gRPC. [Momento Topics](https://docs.momentohq.com/topics) is a popular option for a managed gRPC-based communication tool.
* **MQTT** - [AWS IoT Core](https://aws.amazon.com/iot-core/) offers a managed MQTT message broker, giving you easy access to your devices. Fun fact, this is what powers the notifications in [Serverlesspresso](https://serverlessland.com/reinvent2021/serverlesspresso).
* **Server-Sent Events** - AWS does not provide a native service for managing SSE. However, many popular frameworks have built-in support for it, like [express-sse](https://www.npmjs.com/package/express-sse) for Node.js, [Django](https://pypi.org/project/django-eventstream/) for Python, [rails](https://api.rubyonrails.org/classes/ActionController/Live/SSE.html) for Ruby, and [Spring](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/SseEmitter.html) for Java.

## Testing

Testing server-to-client communications typically has been a tricky task. Personally, I've built server-side workflows that emit events and had to write custom scripts that connect, sit, and wait for the client to do assertions. It's a whole big thing and not a particularly easy way to validate your code. That said, I've found an easier alternative for testing when doing development work.

[Postman](https://postman.com) offers support for WebSockets, gRPC, [MQTT](https://blog.postman.com/postman-supports-mqtt-apis/), and server-sent events. It even provides a wrapper around Socket.IO if you choose to use that.

![Options for request types you can test in Postman](https://readysetcloud.s3.amazonaws.com/notification_protocols_2.png)

Now, all these options are for manual testing, which really only scales when you are in active development. But being able to guess and check your work as you build is a huge productivity boost.

For WebSockets, you can add your endpoint and auth headers, hit *Connect* and go. This was an invaluable resource for me to debug when I was implementing WebSockets via Amazon API Gateway.

If you're building an app that communicates with IoT devices, the MQTT option in Postman will let you select which topics to subscribe to along with the Quality of Service (QOS) for each. You can even configure the Last Will and Testament for the connection to test that out too.

![MQTT configuration in Postman](https://readysetcloud.s3.amazonaws.com/notification_protocols_3.png)

The gRPC request testing capabilities are complete as well, allowing you to import a *.proto* definition file for your schema and add metadata to your messages. You can run assertions via an *After response* script that can check for things like specific metadata or trailers.

The simplest one which makes you go *why didn't I think of that* is server-sent events. Since SSE just uses an HTTP connection, you can [use a standard HTTP request](https://blog.postman.com/support-for-server-sent-events/) in Postman to setup the connection. It will manage the connection and stream the events in the response section as they come in.

I've yet to find a good, managed solution for automated testing in a CI pipeline. For now, I'm sticking with custom scripts when I absolutely have to do it. It's an overhead that you'll need to consider when building your notification mechanisms.

## Go Build

There's a reason there is so much support for real-time notifications: **they are important**! These types of notifications are quickly becoming a de facto standard and if your application doesn't implement one of them, you're likely falling behind. It's something users are inadvertantly beginning to assume exist as part of a core feature set. They don't want to wait or reload pages.

> The world has gone async, and real-time notifications are the tool that ties it all back to your users.

If you're looking to get started, you have lots of options:

* [Amazon API Gateway WebSocket tutorial](https://dev.to/aws-builders/intro-to-aws-websockets-306p) - This will teach you about the many components of WebSockets and comes with functionally complete source code you can deploy.
* [AWS AppSync Subscriptions](https://blog.focusotter.com/trigger-appsync-subscriptions-with-eventbridge-targets) - If you're more of a GraphQL person, [Michael Liendo](https://twitter.com/focusotter) has you covered in this complete guide.
* [Building a reaction app with Momento Topics](https://www.gomomento.com/blog/building-an-interactive-live-reaction-app-with-next-js-and-momento) - Use a managed gRPC-based mechanism to build browser-to-browser commnications without implementing backend services.
* [Developing real-time web apps with Server-Sent Events](https://auth0.com/blog/developing-real-time-web-applications-with-server-sent-events/) - An oldie but a goodie from Auth0 showing how to build with SSE using a React front-end.

There's not a right or wrong way to implement real-time notifications (don't quote me on that). All of us have our own unique business needs that make one mechanism more advantageous over another. The best thing you can do is go out and try. Don't be afraid to iterate. See what works well for you, meets your latency SLAs, and provides a maintainable code base for your devs over the life of your app.

Good luck and if you have any questions, feel free to reach out!

Happy coding!