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

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

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

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

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

#ソース
```javascript: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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737206/2c3d1547-6344-d72f-4e6e-30053c9610b6.gif)
　

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

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