kintoneとAWS Lambda を連携させて、
[kintoneレコード追加] → [Webhook発火] → [API Gateway] → [AWS Lambda] → [AWS Lambda] → [kintoneレコードコメント書き込み] をやってみました。
仕組みイメージ
実行環境
- macOS 10
- AWS Cloud9
- kintone
前提条件
- kintoneでWebhookを設定済み
- AWSアカウント取得済み
- API Gateway設定出来る
- AWS Lambda作成出来る
- AWS CloudWatch利用出来る
- JavaScript, Node.js書ける
- 何らかのSDKを使った経験がある
- AWSで課金されることを理解している
どんなことが出来るか
Webhookを設定したkintoneアプリにレコードを追加します。
Webhookが発火して、[AWS API Gateway]経由で1つ目のLambdaを実行します。1つ目のLambdaは直ぐにkintoneへレスポンスを返して、2つ目のLambdaを実行します。2つ目のLambdaでWebhook通知を発火したkintoneアプリのレコードにコメントを書き込みます。
レコード詳細画面をリロードするとコメントを使う設定になっていれば、追加したレコードのコメントに書き込みがあるはずです。
事前準備
下記拙稿をご覧下さい。
- AWS Cloud9 で AWS Lambda を開発する環境を構築してみる
- AWS Cloud9 で 作成した AWS Lambda 関数で kintone Webhook 通知を受信する
- AWS Lambda 関数から 別の Lambda 関数を呼び出す方法
処理内容の説明
処理の流れに沿って、処理の中の重要な点を説明します。
kintoneのレコードを追加したことをWebhookで通知する
kintoneにはWebhook機能があります。
以下参照(kintoneヘルプより)
Webhookは、複数のWebサービスを連携するための仕組みです。
kintoneでWebhookを設定すると、次の操作が行われたときに、そのことを外部のWebサービスに通知できます。レコードの追加
レコードの編集
レコードの削除
コメントの書き込み
レコードのステータスの変更
今回このWebhookの仕組みを利用して、通知の内容を AWS Lambda でログに出力して、受信が成功したことを再度kintoneのレコードコメントに書き込みしています。
ただし、コメントの書き込みに対する処理はループしてしまうので、操作種類を見てコメント書き込みの時は、再度kintoneのレコードに書き込む処理を省いています。
Webhook通知を [AWS API Gateway] で受信する
API Gateway は AWS が提供する Web API 作成のサービスです。
REST API サービスを簡単に用意することが出来ます。
今回は最初のLambda関数を実行させる入り口として利用しています。
Webhookの設定で、API Gateway の API エンドポイント(URL) を登録することで、作成した API と紐づけた Lambda関数が実行されます。
最初のLambda関数が実行される
Lambda関数でWebhook通知内の操作の種類を判別して、レコードコメント書き込み以外の場合は、次のLambda関数を実行して、そうで無い場合はそのまま成功ステータスを返しています。
const aws = require('aws-sdk');
"use strict";
let sc;
let result;
let response;
exports.handler = async (event, context, callback) => {
try {
const kintonePost = JSON.parse(event.body);
console.log(kintonePost);
const operationType = kintonePost.type;
console.log(operationType);
if (operationType !== 'ADD_RECORD_COMMENT') {
sc = 200;
result = "kintone comment POST success!";
response = {
statusCode: sc,
headers: { "Content-type": "application/json" },
body: JSON.stringify( result )
};
let lambda = new aws.Lambda({apiVersion: '2015-03-31'});
const params = {
FunctionName: "<arn>",
InvocationType: "RequestResponse",
Payload: JSON.stringify(event)
};
console.log(params);
lambda.invoke(params, (err, data) => {
let res = data;
if (err) {
console.log("invoke error.");
console.log(err);
context.done(err, err);
} else {
console.log("invoke success.");
console.log("response:", res);
context.done(null, res);
}
});
} else {
sc = 200;
result = "kintone Record POST success!";
response = {
statusCode: sc,
headers: { "Content-type": "application/json" },
body: JSON.stringify( result )
};
}
} catch(err) {
sc = 400;
result = err.message;
response = {
statusCode: sc,
headers: { "Content-type": "application/json" },
body: JSON.stringify( result )
};
}
callback(null, response);
};
2つ目のLambdaでkintoneのレコードコメントに書き込み
2つ目のLambda関数に処理が渡った際に、Webhookが発火したkintoneアプリの同じレコードのレコードコメントに kintoneのREST APIを叩いてコメントを書き込んでいます。
let requestPromise = require('request-promise');
"use strict";
const env = process.env;
const url = 'https://' + env.SUBDOMAIN + '/k/v1/';
const headers = {'X-Cybozu-API-Token': env.APITOKEN, 'Content-Type': 'application/json'};
let sc; // status code
let result; // Response payload
exports.handler = async (event, context, callback) => {
console.log(event);
const kintonePost = JSON.parse(event.body);
console.log(kintonePost);
const operationType = kintonePost.type;
const kintonePostComment = (kintonePost) => {
const req_body = {
"app": kintonePost.app.id,
"record": kintonePost.record['$id'].value,
"comment": {
"text": "操作種類:" + operationType + "\nAWS Lambdaからのコメント書き込みです。\nご確認をお願いします。"
}
};
const option = {
url: url + 'record/comment.json',
method: 'POST',
headers: headers,
json: req_body
};
return requestPromise(option)
.then((response)=>{
context.done(null, {text: "kintone comment POST success!"});
sc = 200;
result = "kintone comment POST success!";
let callback = {
statusCode: sc,
headers: { "Content-type": "application/json" },
body: JSON.stringify( result )
};
return callback;
})
.catch((error)=>{
console.error('kintone Post Comment failed:', error);
sc = 400;
result = error;
let callback = {
statusCode: sc,
headers: { "Content-type": "application/json" },
body: JSON.stringify( result )
};
return callback;
});
};
let kintonePostResponse;
if (operationType !== 'ADD_RECORD_COMMENT') {
kintonePostResponse = await kintonePostComment(kintonePost);
console.log(kintonePostResponse);
} else {
sc = 200;
result = "kintone Record POST success!";
let callback = {
statusCode: sc,
headers: { "Content-type": "application/json" },
body: JSON.stringify( result )
};
kintonePostResponse = callback;
}
callback(null, kintonePostResponse);
};
あとがき
普段 VS Code を利用してコードを書きますが、
Lambdaの開発については、Cloud9を利用した方が捗るような気がしました。
Cloud9についてはもう少し調べて、出来ればチームで使えるようにしていきたい。
参考リンク
色々と参考にさせていただきました。ありがとうございます。
AWS関連
- AWS SAMを使う前にCloudFormationテンプレートを書こう
- Webhook の受信を契機として複数の API を叩く Lambda 関数を Node.js で書きたいときのためのメモ
- Node.js での AWS Lambda Context オブジェクト
- AWS-SDK AWS.Lambda
- AWS-SDK AWS.Lambda invoke