Ruben Driezen
Ruben Driezen

Reputation: 70

How to update all clients when a webhook is recieved in Python Flask

I have a Flask server with a webhook endpoint for Meraki Alerts ("host_url/endpoint").
The server also has a page which is supposed to display all recieved alerts ("host_url/view").

What I would love to happen is that when Meraki sends a webhook to my endpoint all the clients on "host_url/view" update to show the latest alerts.

I have tried simply polling every few seconds, but even though it works I would like to avoid this solution.

I also tried using websockets, but the standard flask_socketio implementation requires messages send from the server to be within functions decorated with an @socketio.on("...") decorator.

E.g.

@socketio.on("connect")
def send_message():
    emit("msg")

But since the event that triggers such a message isn't a websocket event in itself I need to be able to send messages outside of a socketio function.

E.g.

def send_message():
    emit("msg")

My goal is to have a function send_to_all_clients(data) that I can use from everywhere in my code and that sends an event that can be recieved by a Javascript event handler.

Upvotes: 0

Views: 134

Answers (1)

Detlef
Detlef

Reputation: 8542

To send an event to all clients, I recommend taking a look at the “Broadcasting” section of the Flask-SocketIO documentation. Here it is described how you can use socketio.emit(eventName, data) to send an event, for example from a normal route, so that it can be received by all connected clients.

In the following example, at the push of a button an example event is sent to the webhook, which is then passed on to all clients. Using Postman would certainly be more advisable.

from flask import (
    Flask, 
    render_template, 
    request
)
from flask_socketio import SocketIO

app = Flask(__name__)
sock = SocketIO(app)

@app.route('/')
def index():
    return render_template('index.html')

def send_to_all_clients(data):
    sock.emit('details', data)

@app.post('/webhook')
def webhook():
    data = request.get_json(force=True)
    send_to_all_clients(data)
    return '', 200

if __name__ == '__main__':
    sock.run(app)
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Index</title>
</head>
<body>
    <button id="snd">Call Webhook</button>
    <pre><output id="out"></output></pre>

    <script 
        src="https://cdn.socket.io/4.7.2/socket.io.min.js" 
        integrity="sha384-mZLF4UVrpi/QTWPA7BjNPEnkIfRFn4ZEO3Qt/HFklTJBj/gBOV8G3HcKn4NfQblz" 
        crossorigin="anonymous"></script>

    <script>
        (function() {
            const sock = io();
            sock.on('details', (...args) => {
                const elem = document.getElementById('out');
                elem.innerText += JSON.stringify(args) + '\n';
            });

            document.getElementById('snd').addEventListener('click', () => {
                const data = {
                    "version": "0.1",
                    "sharedSecret": "secret",
                    "sentAt": "2021-10-07T08:38:40.522804Z",
                    "organizationId": "2930418",
                    "organizationName": "My organization",
                    "organizationUrl": "https://dashboard.meraki.com/o/VjjsAd/manage/organization/overview",
                    "networkId": "N_24329156",
                    "networkName": "Main Office",
                    "networkUrl": "https://n1.meraki.com//n//manage/nodes/list",
                    "networkTags": [],
                    "deviceSerial": "Q234-ABCD-5678",
                    "deviceMac": "00:11:22:33:44:55",
                    "deviceName": "My access point",
                    "deviceUrl": "https://n1.meraki.com//n//manage/nodes/new_list/000000000000",
                    "deviceTags": [
                        "tag1",
                        "tag2"
                    ],
                    "deviceModel": "MR",
                    "alertId": "0000000000000000",
                    "alertType": "APs came up",
                    "alertTypeId": "started_reporting",
                    "alertLevel": "informational",
                    "occurredAt": "2018-02-11T00:00:00.123450Z",
                    "alertData": {}
                };
                fetch('/webhook', {
                    method: 'post', 
                    body: JSON.stringify(data)
                });
            })
        })();
    </script>
</body>
</html>

Upvotes: 1

Related Questions