SendGridのイベントをSocket.IOでプッシュ表示する
SendGridのEvent Webhookでイベントを確認するとき、Request BinやWebhook.siteのようなサイトをよく使います。同じようなものを自前で作りたいけど、サーバサイドで受信したPOSTデータをどうやってクライアント(ブラウザ)にプッシュ表示するんだっけ...と思って昔聞いたWebSocketやSSE(Server-Sent Events)を調べていたところSocket.IOを知りました。
試したところ簡単に実装できたのでまとめます。環境はdocker上のalpine linux 3.15.0&Node.js 17.3.0です。
app.js
まずはサーバサイドです。こちらで書いたapp.jsに対してSocket.IOのGet Startedのサーバサイドを参考に書きました。
const express = require('express');
const { createServer } = require('http');
const { Server } = require('socket.io');
const bodyParser = require('body-parser');
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer);
app.use(bodyParser.json());
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
app.post('/', (req, res) => {
io.emit('message', JSON.stringify(req.body));
res.sendStatus(200);
});
io.on('connection', socket => {
console.log('connection');
socket.on('disconnect', () => {
console.log('disconnect');
});
});
httpServer.listen(3000);
当初POST部分は以下のように書いていたのですが、SendGridのEvent WebhookはJSONオブジェクトの配列が入るため、何もしないとクライアント側では[object Object],[object Object]...のような表示になってしまうためJSON.stringfyで文字列に変換しました。(使い方あってるのかな...)
app.post('/', (req, res) => {
io.emit('message', req.body);
res.sendStatus(200);
});
index.html
クライアントのHTMLです。socket.io.min.jsはCDNのものを利用しました。pタグにサーバから受け取ったデータを追加するだけです。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SendGrid Event Webhook</title>
</head>
<body>
<p id="message"></p>
<script src="https://cdn.socket.io/4.4.0/socket.io.min.js" integrity="sha384-1fOn6VtTq3PWwfsOrk45LnYcGosJwzMHv+Xh/Jx5303FVOXzEnw0EpLv30mtjmlj" crossorigin="anonymous"></script>
<script>
const socket = io();
var message = document.getElementById("message");
socket.on('message', msg => {
message.innerHTML += msg;
});
</script>
</body>
</html>
実行結果
動作確認はこちらの手順でlocaltunnelを使ったローカル環境で行いました。
アクセスすると初めは何も表示されていない状態です。Event Webhookの「Test Your Integration」を押してPOSTデータを受信するとサーバからクライアント(ブラウザ)にプッシュ表示します。
これをどこかにホスティングすればRequestBinみたいに使えるはず。
Discussion