Simple realtime notifications
Tags: webdev, vue, python, architecture
Published: 2020-06-14 15:55:22

> We will use Vue.js + FastAPI + Pusher

Let’s all accept the fact that any modern web application can’t live without realtime notifications. If your cool shiny service doesn’t have them yet, there is a 99% chance that it is somewhere there in your backlog.

> Today, speed of delivery is the level of quality.

In other words, there is no question *WHY*, there is another question — __HOW__?

## Target Architecture

![Managers must get immediate notifications when Customer orders something](https://miro.medium.com/max/1400/1*HKOwbCPB-4SUW4EekLuz5A.png)

We would want something like that. Let’s briefly discuss details on this E-Commerce example:

* Our Frontend has 2 portals: *Online Store for Customers* and *CRM for Managers*
* Our Backend has microservices architecture with a message bus for communication between services
* We have many services in Backend, but only two are important for this example: *Orders* and *Events*
* Backend services are written in everything from Cobol to Go, but for events we want something simple and reasonable like __Python__
* We want some free SaaS like [Pusher](https://pusher.com/) to handle realtime notification complexity for us (we are too greedy to pay from the start and too lazy to work with websockets on our own)
* We must be able to send the same notification to a group of managers (let them battle for the client!)
* Notifications need privacy as there may be some sensitive user information (we state that we don’t sell user data, usually).

## Proof Of Concept

![PoC](https://miro.medium.com/max/1400/1*L5KhZjP6QcZKl9rbMQ61rw.png)

For the proof of concept we can simplify everything even more:

* We don’t care how messages will appear in our *Events* service — a simple manual script will be totally enough
* We won’t create complex Authentication/Authorization for *Events Auth* call as we will test only locally
* No Fancy UI in Frontend, a simple text notification is fine for PoC

## SaaS

Pusher with [Pusher Channels](https://pusher.com/channels) seems like a perfect fit for our needs. It offers a generous free plan for getting started: *100 max connections, 200k messages per day, SSL protection, unlimited channels and 99.997% API uptime*. There is also a great [Pusher Channels Python SDK](https://github.com/pusher/pusher-http-python), which has backends for sync and async code. And last but not least, it’s used by our beloved GitHub.

> Pusher also provides the [Beams platform](https://pusher.com/beams) for mobile push messages (web is in beta at the moment). If you need to support such kind of notifications, it seems like a great tool to try. Though, you need to be warned that at this moment [Python SDK for Beams](https://github.com/pusher/push-notifications-python) doesn’t provide support for async code. It doesn’t seem like a big problem as Beams API is pretty simple, but it will take some efforts to integrate.

For the code in the next paragraphs we will use some of Pusher Channels Environment Variables, which can be found in the *App Key* section of the created application in [Pusher Dashboard](https://dashboard.pusher.com/).

## CRM Portal

Let’s start writing code already! Our CRM portal will consist only from one HTML page with the simplest Vue Application inside.

{% gist https://gist.github.com/maxipavlovic/4a2534dd5967c683ad716b2a16da0425 %}

As you can see, the code is pretty simple. We create a Pusher instance with custom authentication endpoint and subscribe it to the private channel *private-foobar*. If we will open the page right now, authentication will fail and we won’t be able to receive our events. Let’s implement our Events service to fix that.

## Events Service

Our service will have the following requirements.

```python
pusher              # Pusher Channels SDK
aiohttp             # Async HTTP client for Pusher Backend
fastapi             # Fast and Modern API Framework
uvicorn             # ASGI server to run our API
python-multipart    # Support for Forms in FastAPI
python-dotenv       # Loading of variables from .env
```

We will start with initialization of Pusher client:

{% gist https://gist.github.com/maxipavlovic/a4be2aa766b7114654f04694052582eb %}

For local development we need to enable *CORSMiddleware* with any origin (*restrict origins for production usage!*). __pusher_auth__ implementation is done according to the [Pusher Authentication Specification](https://pusher.com/docs/channels/server_api/authenticating-users). We can now run our API!

```consoleLog
uvicorn api:app --reload
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [83155] using statreload
INFO:     Started server process [83157]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
```

We can now open our CRM Portal and authentication will be successful. Now, we have only one thing left — event generation. We will write the following simple script:

{% gist https://gist.github.com/maxipavlovic/23ebd47696285d22b13be83207dee1b6 %}

Let’s call it to see if we get the notification in our web Portal. And there it is:
![PoC](https://miro.medium.com/max/1400/1*fUuCi_36cj7-Wyjp8vxdIA.png)

If we open several tabs with the same CRM portal, we will see that each tab receives “hello world” message.

The concept has just been successfully proved 🥳! Here is the repository for you to play with.

{% github maxipavlovic/chapushillo no-readme %}