初めに
LINEmessagingAPI + WebAPIで、位置情報を送ると近くの宿泊施設を返してくれるLINEBotを作成しました。
ついでに最寄り駅も返します。
利用したAPI
■楽天トラベル施設検索API(宿泊施設の検索)
https://webservice.rakuten.co.jp/api/simplehotelsearch/
■HeartRails Geo API(最寄り駅の検索)
http://geoapi.heartrails.com/
コード
'use strict'; // おまじない
// ########################################
// 初期設定など
// ########################################
// パッケージを使用します
const express = require('express');
const line = require('@line/bot-sdk');
const axios = require('axios');
// ローカル(自分のPC)でサーバーを公開するときのポート番号です
const PORT = process.env.PORT || 10000;
// Messaging APIで利用するクレデンシャル(秘匿情報)です。
const config = {
channelSecret: '作成したBotのチャネルシークレット',
channelAccessToken: '作成したBotのチャネルアクセストーク'
};
// ########## ▼▼▼ サンプル関数 ▼▼▼ ##########
const sampleFunction = async (event) => {
// ユーザーメッセージが位置情報かどうか
if (event.message.type == 'location') {
let pushText = '';
const latitude = event.message.latitude;
const longitude = event.message.longitude;
const postNumber = event.message.address.split('〒')[1].split(' ')[0].replace('-','');
//楽天トラベル施設検索APIで、指定された位置情報から半径1km以内の宿を検索(おすすめ順・5件)
client.pushMessage(event.source.userId, {
type: 'text',
text: '1km以内の宿泊施設を検索します。',
});
try {
const rakuten = await axios.get('https://app.rakuten.co.jp/services/api/Travel/SimpleHotelSearch/20170426?applicationId=アプリID&format=json&latitude=' + latitude + '&longitude=' + longitude + '&searchRadius=1&datumType=1&hits=5');
for(let i in rakuten.data.hotels){
client.pushMessage(event.source.userId, {
type: 'text',
text: rakuten.data.hotels[i]['hotel'][0]['hotelBasicInfo']['hotelInformationUrl'],
});
}
} catch (error) {
pushText = '楽天検索中にエラーが発生しました。ごめんね。';
// APIからエラーが返ってきたらターミナルに表示する
console.error(error);
client.pushMessage(event.source.userId, {
type: 'text',
text: pushText,
});
}
//郵便番号から最寄駅を検索
try {
const station = await axios.get('http://geoapi.heartrails.com/api/json?method=getStations&postal=' + postNumber);
client.pushMessage(event.source.userId, {
type: 'text',
text: '最寄り駅は' + station.data['response']['station'][0].name + '駅です。',
});
} catch (error) {
pushText = '最寄り駅検索中にエラーが発生しました。ごめんね。';
// APIからエラーが返ってきたらターミナルに表示する
console.error(error);
client.pushMessage(event.source.userId, {
type: 'text',
text: pushText,
});
}
return await client.pushMessage(event.source.userId, {
type: 'text',
text: '良い旅を。',
});
}
};
// ########## ▲▲▲ サンプル関数 ▲▲▲ ##########
// ########################################
// LINEサーバーからのWebhookデータを処理する部分
// ########################################
// LINE SDKを初期化します
const client = new line.Client(config);
// LINEサーバーからWebhookがあると「サーバー部分」から以下の "handleEvent" という関数が呼び出されます
async function handleEvent(event) {
// 受信したWebhookが「テキストメッセージ以外」であればnullを返すことで無視します
//if (event.type !== 'message' || event.message.type !== 'text') {
// return Promise.resolve(null);
//}
// サンプル関数を実行します
return sampleFunction(event);
}
// ########################################
// Expressによるサーバー部分
// ########################################
// expressを初期化します
const app = express();
// HTTP POSTによって '/webhook' のパスにアクセスがあったら、POSTされた内容に応じて様々な処理をします
app.post('/webhook', line.middleware(config), (req, res) => {
// Webhookの中身を確認用にターミナルに表示します
console.log(req.body.events);
// 検証ボタンをクリックしたときに飛んできたWebhookを受信したときのみ以下のif文内を実行
if (req.body.events[0].replyToken === '00000000000000000000000000000000' && req.body.events[1].replyToken === 'ffffffffffffffffffffffffffffffff') {
res.send('Hello LINE BOT! (HTTP POST)'); // LINEサーバーに返答します
console.log('検証イベントを受信しました!'); // ターミナルに表示します
return; // これより下は実行されません
}
// あらかじめ宣言しておいた "handleEvent" 関数にWebhookの中身を渡して処理してもらい、
// 関数から戻ってきたデータをそのままLINEサーバーに「レスポンス」として返します
Promise.all(req.body.events.map(handleEvent)).then((result) => res.json(result));
});
// 最初に決めたポート番号でサーバーをPC内だけに公開します
// (環境によってはローカルネットワーク内にも公開されます)
app.listen(PORT);
console.log(`ポート${PORT}番でExpressサーバーを実行中です…`);
結果
実行結果です。
課題・考察
・最寄り駅の取得ができない場合がある
原因:LINEで位置情報を送る際、施設を指定すると郵便番号が送られない
対策:住所情報→郵便番号変換→最寄り駅検索の処理に変更する
・対話型で検索条件をより柔軟にしたい
楽天トラベル施設検索APIを利用する際、検索条件は「おすすめ順」で5件表示としていますが、
Botとの会話で「値段が安い順」などを設定して検索できればより使いやすいなと感じました。
位置情報を利用したAPIは他にもいくつもあるので、さらに組み合わせるともっと便利なBotになる気がします。
宿検索してそのまま予約までできるんじゃないかな。