【PWA】シリーズPWA (9) APIを実装する
Expressが提供するAPI自体を実装します。
基本的には第7回で紹介した内容を、Expressの文法に落とし込んでゆく感じになります。
ここで登場するsubscriptionsという変数には前回でSqualizeによって作成されたORマッパーのオブジェクト(DBにデータの追加や削除や他にもごにょごにょできるオブジェクト)が格納されています
add (レコードの追加)
app.post('/add', function(req, res) { let data = req.body; let response = res; subscriptions.create({ registrationID: data.registrationID, publicKey: data.key, auth: data.auth, endpoint: data.endpoint }).then(function(){ response.setHeader('Content-Type', 'text/plain'); response.end('New subscriptions is successfully added.'); }); });
delete(レコードの削除フラグをTRUEに)
クライアントからは削除するregistrationIDがわたってくる想定です。
app.post('/delete', function(req, res) { let data = req.body; subscriptions.update({ deleted: true },{ where: { registrationID: data.registrationID } }); });
push
ここは、これまでに登場したロジックを再利用することができます。
app.post('/push', function(req, res) { let response = res; let data = req.body; let subscribers = []; // 通知の内容 const params = { title: data.title, msg: data.message, icon: '/path/to/icon' }; webpush.setVapidDetails( 'admin@xxx.jp', 'Firebase Consoleから取得した公開鍵', 'Firebase Consoleから取得した秘密鍵' ); subscriptions.findAll({ where: { deleted : false } }).then(function(rows){ // 利用可能なサブスクリプションを配列に追加 rows.forEach(function (row) { let subscription = {}; subscription.endpoint = row.endpoint; subscription.expirationTime = null; subscription.keys = { p256dh: row.publicKey, auth: row.auth }; subscribers.push(subscription); }); // 利用可能なサブスクリプション全てに対して通知を発信 Promise.all(subscribers.map(subscription => { return webpush.sendNotification(subscription, JSON.stringify(params), {}); })) .then(function(res){ response.setHeader('Content-Type', 'text/plain'); response.end('Request data is successfully pushed.'); }) .catch(function(err){ console.log('ERROR', err); }); }); });
これらを合わせると以下のようになります。
const express = require('express'); const webpush = require('web-push'); const bodyParser = require('body-parser'); const Sequelize = require('sequelize'); const app = express(); // CORSを許可する app.use(function(req, res, next) { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); next(); }); // urlencodedとjsonは別々に初期化する app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); // DBに接続 const sequelize = new Sequelize('接続文字列', { logging: false, operatorsAliases: false }) // テーブルを作成 const subscriptions = sequelize.define('subscriptions', { id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true }, registrationID: { type: Sequelize.STRING, allowNull: false }, publicKey: { type: Sequelize.STRING, allowNull: false }, auth: { type: Sequelize.STRING, allowNull: false }, endpoint: { type: Sequelize.STRING, allowNull: false }, deleted: { type: Sequelize.BOOLEAN, allowNull: false, defaultValue: false } }, { freezeTableName: true, timestamps: true, indexes:[{ unique: false, fields:['deleted'] }] }); subscriptions.sync(); // ルートにアクセスされたら文字列を表示 app.get('/', function(req, res) { res.setHeader('Content-Type', 'text/plain'); res.send('This is PWA Test App'); }); // addでアクセスされたらサブスクリプションをDBに追加する app.post('/add', function(req, res) { let data = req.body; let response = res; subscriptions.create({ registrationID: data.registrationID, publicKey: data.key, auth: data.auth, endpoint: data.endpoint }).then(function(){ response.setHeader('Content-Type', 'text/plain'); response.end('New subscriptions is successfully added.'); }); }); // deleteでアクセスされたら古いサブスクリプションの削除フラグをtrueにする app.post('/delete', function(req, res) { let data = req.body; subscriptions.update({ deleted: true },{ where: { registrationID: data.registrationID } }); }); // pushでアクセスされたら削除フラグがfalseのものに対して通知を送る app.post('/push', function(req, res) { let response = res; let data = req.body; let subscribers = []; // 通知の内容 const params = { title: data.title, msg: data.message, icon: '/path/to/icon' }; webpush.setVapidDetails( 'admin@xxx.jp', 'Firebase Consoleから取得した公開鍵', 'Firebase Consoleから取得した秘密鍵' ); subscriptions.findAll({ where: { deleted : false } }).then(function(rows){ // 利用可能なサブスクリプションを配列に追加 rows.forEach(function (row) { let subscription = {}; subscription.endpoint = row.endpoint; subscription.expirationTime = null; subscription.keys = { p256dh: row.publicKey, auth: row.auth }; subscribers.push(subscription); }); Promise.all(subscribers.map(subscription => { return webpush.sendNotification(subscription, JSON.stringify(params), {}); })) .then(function(res){ response.setHeader('Content-Type', 'text/plain'); response.end('Request data is successfully pushed.'); }) .catch(function(err){ console.log('ERROR', err); }); }); }); // サーバ起動 const server = app.listen(process.env.PORT || 8000);
次回予告
以上で、サブスクリプション をDBで管理し、有効なものにだけ通知を発信する仕組みができました。 続いて、このプログラムを叩く、クライアント側の実装を行います。