2016-04-14

FacebookのMessenger用Botをforce.comで作ってみた

今度は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;
    }
    ...
}

上記例の場合、設定値は

になります。

ユーザへのメッセージ送信

こんな感じで。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ページでメッセージを送ると良い感じに返してくれます↓

facebook-bot-keyaki

参考URL

このエントリーをはてなブックマークに追加