LoginSignup
7
1

More than 3 years have passed since last update.

LINE Messaging APIを使ってブルワリーを探してみた

Last updated at Posted at 2020-10-10

目的

 LINEBotを使って、対話でうまくブルワリーの情報を探したい!
 なぜLINEか?
 ⇒老若男女問わず使えるインターフェースですから!
 なぜブルワリーか?
 ⇒お酒が、、好きなんです。

前提

 記事を読まれる前に、、、
 まだまだやりたいことの最初の慣れの部分なので、
 えっ?なんで?と思うことは多いかと思います。

今回やったこと

 ブルワリー検索APIの「Open Brewery DB」と「LINE MessagingAPI」を使って、
 LINEのトーク画面からニューヨークのブルワリーを検索して、一覧をLINEのレスポンスとして返す。
 URL付きでページにとんだり、電話をかけやすくするなど。

やってみてわかったこと

 ★流れが何となく見えた。
 ユーザがLINEから何かメッセージをうつ。
 →LINEサーバにまず送られる。
 →LINEのサーバからWebhookでイベントがとんでくる。
 →イベントの何を取るのか、チェックしつつ、来た内容に対してどう返すかをプログラムで作る。
 
 リクエストのイベントが来るところの受け方は、
 詳しくはLINEのドキュメントをもっと見たほうが良いと思った。
 https://developers.line.biz/ja/reference/messaging-api/

ソース

brewery_server.js
 'use strict'; // おまじない

// ########################################
//               初期設定など
// ########################################

// パッケージを使用します
const express = require('express');
const line = require('@line/bot-sdk');
const axios = require('axios');
const fs = require('fs');

// ローカル(自分のPC)でサーバーを公開するときのポート番号です
const PORT = process.env.PORT || 3000;

// Messaging APIで利用するクレデンシャル(秘匿情報)です。
const credential = JSON.parse(fs.readFileSync('./credential/credential.json', 'utf8'));

const config = {
    channelSecret: credential.channelSecret,
    channelAccessToken: credential.channelAccessToken
};


// ユーザのメッセージに対してどう返すかを定義
const sampleFunction = async (event) => {
    // ユーザーメッセージが想定しているものかどうか
    if (check_params(event.message.text)) {
        return client.replyMessage(event.replyToken, {
            type: 'text',
            text: 'ニューヨークのブルワリーは?と話しかけてね'
        });
    } else {
        // 「リプライ」を使って先に返事しておきます
        await client.replyMessage(event.replyToken, {
            type: 'text',
            text: '調べています……'
        });

        let pushText = '';
        try {
            // axiosでニューヨークブルワリーリストのAPIを叩きます(少し時間がかかる・ブロッキングする)
            const res = await axios.get('https://api.openbrewerydb.org/breweries?by_state=new_york');
            console.log(res.data);
            const brewery_data = res.data;
            for (let j =0 ; j<brewery_data.length ; j++) {
                const b_name = brewery_data[j].name;
                const b_url = brewery_data[j].website_url;
                console.log(b_name);
                if(j === 0){
                    pushText = 'ここ!\r\n';

                }else{
                    pushText = pushText + '店名 ' + b_name + '\r\n' + 'URL ' + b_url + '\r\n\r\n';
                }
            }
        } catch (error) {
            pushText = '検索中にエラーが発生しました。ごめんね。';
            // APIからエラーが返ってきたらターミナルに表示する
            console.error(error);
        }

        // 「プッシュ」で後からユーザーに通知します
        return client.pushMessage(event.source.userId, {
            type: 'text',
            text: pushText,
        });
    }
};


function check_params(event_text) {
    if(event_text === 'ニューヨークのブルワリーは?'){
        return false;
    }else {
        return true;
    }

}

// ########################################
//  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サーバーを実行中です…`);

環境

 Node.js v14.9.0
 Visual Studio Code v1.49.3
 @line/bot-sdk

結果

 brewery.gif
 

【おまけ】本当は、やれたらやりたいこと

■技術
 ・ユーザから送られたメッセージのチェック(関数切り出し)
 ・LINEに表示された際に、URLから取得されたサイトのサムネイル?がMAX5件ぐらいなので、
  取得も5件ぐらいの方が見やすそう。
 ・認証情報は、見えそうなファイルよりも、もっと隠れたところから取得したほうが良いと思う。
 ・リッチメニューを使ってそもそもどんな操作をすればよいのかユーザにわかりやすくする。
  (フリーテキストって何入れればええのかわからない。)
 ・Googleマップのリンクを付けて保存しやすくする。

■企画
 ・ビールも好きだけど、肉やカレーも。。。

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1