第3回になりました。
過去のはこちら。
今回は、ようやくやりたいことに近づいて来まして
slackからのリクエストをlambdaで受けられるようにしたいと思います。
何か調べていくと、どうもAPI Gatewayを使うと良い感じぽい。
まずはAPI Gatewayについて予習を。
API Gateway
どんな役割をしてくれるのか
APIのエンドポイントとして待ち構える玄関として使える
現在はhoge/*
のようなパスを/hoge/{proxy+}
として設定できる
プロキシリソースなるものらしい
post, putの振り分けなどが簡単になった
課金体系
受信した API 呼び出しと、送出したデータ量に対して発生
serverless frameworkでの設定
functions:
bookStore:
handler: books/store.store
events:
- http:
path: books
method: get
cors: true
これだけ。
デプロイ実行すると
$ serverless deploy -v --stage dev
Serverless: Packaging service...
・
・
CloudFormation - CREATE_IN_PROGRESS - AWS::ApiGateway::Deployment - ApiGatewayDeployment1490662361327
CloudFormation - CREATE_IN_PROGRESS - AWS::ApiGateway::Deployment - ApiGatewayDeployment1490662361327
CloudFormation - CREATE_COMPLETE - AWS::ApiGateway::Deployment - ApiGatewayDeployment1490662361327
・
・
Service Information
service: testProject
stage: dev
region: ap-northeast-1
api keys:
None
endpoints:
GET - https://xxxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/books
functions:
bookStore: testProject-dev-bookStore
エンドポイントが作られた。。!
レスポンスを送れるか試してみる
$ curl https://xxxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/books
{"message":"ok",...........}
うん、okそう、すごい。ymlに書くだけで何でも設定してくれちゃう。
Slackから応答させるようにする
ここで今回の本題。
作成したエンドポイントに対してスラックがリクエストを送って
slack上にメッセージが返ってくるようにする。
全体像
やることとしては、リクエストパラメータを解析してデータを保存。
保存した結果を返す
'use strict';
const slackAuthorizer = require('../authorizer/slackAuthorizer');
const parser = require('../service/queryParser');
const bookSave = require('../useCase/book/save.js');
module.exports.book = (event, context, callback) => {
const queryParser = new parser(event.body);
const authorizer = new slackAuthorizer(queryParser.parseToken());
/**
* 認証
*/
if (!authorizer.authorize()) {
context.done('Unauthorized');
}
/**
* @Todo ここで lambda function の振り分けを行いたい
*/
bookSave(event, (error, result) => {});
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'ok',
}),
};
callback(null, response);
};
同期で処理を行いたいので async
を使って処理をブロックごとに実行する
'use strict';
const AWS = require('aws-sdk');
const dynamoDB = new AWS.DynamoDB.DocumentClient();
const bookTable = process.env.bookTable;
const uuidV1 = require('uuid/v1');
const webhookUrl = process.env.slack_webhook_url;
const request = require('request');
const dateTime = require('node-datetime');
const dt = dateTime.create();
const insertDate = dt.format('Y-m-d H:M:S');
const async = require('async');
const parser = require('../../service/queryParser');
module.exports = (event, callback) => {
const queryParser = new parser(event.body);
const key = uuidV1();
async.series([
function(callback) {
/**
* データを保存
*/
dynamoDB.put({
'TableName': bookTable,
'Item': {
'id': key,
'title': queryParser.parseText(),
'insert_date': insertDate,
},
}, function(err, data) {
callback(null, "saved");
});
},
function(callback) {
/**
* 保存したものを取り出して
* 結果を返す
*/
dynamoDB.get({
TableName: bookTable,
Key: {
id: key,
},
}, function(err, data) {
if (!err) {
const response = {
text: `\`${data.Item.title}\` is Saved !!`,
};
/**
* webhook でチャンネルにメッセージを返す
*/
request.post(webhookUrl, {
form: {
payload: JSON.stringify(response),
},
}, (err, response, body) => {
callback(null, 'getData');
});
}
});
},
], function(err, results) {
if (err) {
throw err;
}
});
};
slash commandから送られてきたパラメータをパースするために
query-string
モジュールを使い、ラップした
'use strict';
const queryStringParser = require('query-string');
module.exports = class queryParser {
constructor (queryString) {
this.queryString = queryString;
}
parseToken () {
return queryStringParser.parse(this.queryString).token;
}
parseText () {
return queryStringParser.parse(this.queryString).text;
}
};
slashコマンドの設定は省略します。
最初の api gatewayで設定されたエンドポイントのURLを
設定してあげればいいので
実際に動かすとこんな感じです。
ソースは汚いかもしれませんが、saverlessフレームワークで
エンドポイント作成やdb、外部サービスの連携が簡単に出来ました
もっとキレイに書けるようにjsの筋力をつけていかねば。。笑