Cloud Datastoreに保存したSendGridのWebhookを参照するGoogle Cloud Functions API
やりたいこと
前回、SendGridのWebhookをDatastoreに貯めるところまで進めた。
tminami.hatenablog.com
今回は保存したデータを取得するAPIを、同じくGoogle Cloud Functionsでつくる。
Cloud Functionsの設定等は前記事参照。
ソース
index.js
const Buffer = require('safe-buffer').Buffer; const Datastore = require('@google-cloud/datastore'); const BASIC_USERNAME = process.env.BASIC_USERNAME; const BASIC_PASSWORD = process.env.BASIC_PASSWORD; const PROJECT_ID = process.env.PROJECT_ID; const datastore = Datastore({projectId: PROJECT_ID}); /** * Verify that the webhook request came from sendgrid. * * @param {string} authorization The authorization header of the request, e.g. "Basic ZmdvOhJhcg==" */ function verifyWebhook (authorization) { const basicAuth = Buffer.from(authorization.replace('Basic ', ''), 'base64').toString(); const parts = basicAuth.split(':'); if (parts[0] !== BASIC_USERNAME || parts[1] !== BASIC_PASSWORD) { const error = new Error('Invalid credentials'); error.code = 401; throw error; } } /** * Receive a webhook from SendGrid. * * See https://sendgrid.com/docs/API_Reference/Webhooks/event.html * * @param {object} req Cloud Function request context. * @param {object} res Cloud Function response context. */ exports.getSendgridWebhook = async (req, res) => { try { if (req.method !== 'POST') { const error = new Error('Only POST requests are accepted'); error.code = 405; throw error; } const sgMessageId = req.body['sg_message_id'] || null; if (!sgMessageId) { const error = new Error('No data error. require sg_message_id.'); error.code = 500; throw error; } const isDesc = req.body['isDesc'] || false; const query = datastore .createQuery('sg_event') .filter('sg_message_id_prefix', '=', sgMessageId) .order('timestamp', { descending: isDesc, }); const results = await datastore.runQuery(query); const json = JSON.stringify(results); res.setHeader('Content-Type', 'application/json'); res.send(JSON.stringify(results)); } catch (err) { console.error(err); res.status(err.code || 500).send(err); }; };
index.js
{ "name": "get-sendgrid-webhook", "version": "0.0.1", "main": "index.js", "dependencies": { "safe-buffer": "^5.1.2", "@google-cloud/datastore": "1.3.4" } }
検索用index作成
上記のindex.jsでは『sg_message_id_prefix』をキーにして、『timestamp』昇順降順を選んでデータを取得している。
keyValue型のデータベースだと複数のプロパティを検索条件にするときはindexを作る必要があるみたい。
今回は以下手順で作成した。
- Cloud Shellを開く
- index.yamlを作成
$ vim index.yaml
- 作成したindex.yamlをもとにインデックス作成
$ gcloud datastore create-indexes index.yaml
index.yaml
indexes: - kind: sg_event properties: - name: sg_message_id_prefix - name: timestamp - kind: sg_event properties: - name: sg_message_id_prefix - name: timestamp direction: desc
APIを叩いてみる
curlだとこんな感じ
curl -H 'BASIC_USERNAME:****' -H 'BASIC_PASSWORD:****' -H 'Content-Type:application/json' -X POST -d '{"sg_message_id":"****","isDesc": false}' 'エンドポイントURL'
所感
実際に使うとなったらインデックスを追加して、『event』のステータスも指定する感じにするか、
APIは汎用的にしておいて呼び出し側でjsonを分解して判定するかになる。(当たり前)