今度はFacebookのMessanger用Botが出たようなので例の通り、force.comで試してみましたー
事前準備
基本的に公式リファレンスのとおりに進めていけばOKです。“Setup Webhook”でエンドポイントの検証をfacebookからのHTTPリクエストによって行いますが、このHTTPリクエストやイベントのコールバックの受信は、Anonymous Apex RESTを利用します。具体的な実装方法は以前の記事を参照。
検証用の処理は以下のように書けばOK
@RestResource(urlMapping='/facebook_callback')
global with sharing class FacebookBotCallback {
...
@httpGet
global static Integer doGet() {
RestRequest req = RestContext.request;
RestResponse res = RestContext.response;
if (req.params.get('hub.verify_token') == 'keyaki_kakenai') {
return Integer.valueOf(req.params.get('hub.challenge'));
}
return 0;
}
...
}
上記例の場合、設定値は
- Callback URL→https://{サイトのドメイン}/services/apexrest/facebook_callback
- Verify Token→keyaki_kakenai
ユーザへのメッセージ送信
こんな感じで。https://graph.facebook.comに対するリモートサイトの設定も忘れずに。public with sharing class FacebookBotClient {
private static final String FACEBOOK_MESSAGE_URL = 'https://graph.facebook.com/v2.6/me/messages';
private String accessToken;
public FacebookBotClient(String accessToken) {
this.accessToken = accessToken;
}
public String sendRequest(String sender, Map<String, Object> content) {
HttpRequest req = new HttpRequest();
req.setHeader('Content-type', 'application/json; charset=UTF-8');
req.setTimeout(60000);
String jsonBody = Json.serialize(new Map<String, Object> {
'recipient' => new Map<String, String> {
'id' => sender
},
'message' => content
});
req.setHeader('Content-Length', String.valueOf(jsonBody.length()));
req.setEndpoint(FACEBOOK_MESSAGE_URL + '?access_token=' + this.accessToken);
req.setMethod('POST');
req.setBody(jsonBody);
Http http = new Http();
HTTPResponse res = http.send(req);
return res.getBody();
}
public String sendTextMessage(String sender, String message) {
return this.sendRequest(sender, new Map<String, String> {
'text' => message
});
}
public String sendImageMessage(String sender, String imageUrl) {
return this.sendRequest(sender, new Map<String, Object> {
'attachment' => new Map<String, Object> {
'type' => 'image',
'payload' => new Map<String, String> {
'url' =>imageUrl
}
}
});
}
}
ユーザからのメッセージ受信
メッセージの受信処理+受信内容に応じてメッセージを返す処理は以下のようになります ※欅坂仕様です@RestResource(urlMapping='/facebook_callback')
global with sharing class FacebookBotCallback {
private static final String FACEBOOK_ACCESS_TOKEN = 'input your access token';
...
@httpPost
global static Map<String, String> doPost() {
RestRequest req = RestContext.request;
RestResponse res = RestContext.response;
Map<String, Object> callbackParams = (Map<String, Object>)JSON.deserializeUntyped(req.requestBody.toString());
Map<String, Object> entry = (Map<String, Object>)((List<Object>)callbackParams.get('entry'))[0];
Map<String, Object> messaging = (Map<String, Object>)((List<Object>)entry.get('messaging'))[0];
Map<String, Object> sender = (Map<String, Object>)messaging.get('sender');
Map<String, Object> message = (Map<String, Object>)messaging.get('message');
if (message == null) {
return null;
}
FacebookBotClient client = new FacebookBotClient(FACEBOOK_ACCESS_TOKEN);
String text = String.valueOf(message.get('text'));
String debugBody = '';
if (text == '欅坂') {
debugBody = client.sendTextMessage(String.valueOf(sender.get('id')), '祝!デビュー曲初週売上 女性歴代最高26万枚!!');
} else if (text == 'ひらてち') {
debugBody = client.sendImageMessage(String.valueOf(sender.get('id')), '{ひらてちの画像URL}');
}
System.debug(debugBody);
return new Map<String, String>{};
}
}
messageがnullのときは”Message-Delivered”等のイベントなので上記例ではスルーしてます。静的型付けな言語なのでシリアライズが冗長気味。あとLINE Botと違って受信側の認証の仕組みが無い(?)っぽいです。コールバックURLを秘匿なURIにするしか無いのかな…。
あとはfacebookページでメッセージを送ると良い感じに返してくれます↓