WikipediaのAPIを使ってLINEbotに調べてもらう

# やったこと
知りたいことをLINE上で質問してすぐ返ってきたら便利だなーと思い、LINEbotさんにWikipediaの頭脳を与えてみました。
初学者なので非効率で汚い書き方をしている所もあるかと思いますが、ご了承ください！


### できたものサンプル
普通にキーワードを入力すると、URLを返してくれる。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">LINEbotにwikipediaAPIを組み込んでみた。その１<br>聞くとURLを返してくれる<a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://t.co/vspklo51fQ">pic.twitter.com/vspklo51fQ</a></p>&mdash; yuta kawashima (@y_kawashima_) <a href="https://twitter.com/y_kawashima_/status/1241398968078053376?ref_src=twsrc%5Etfw">March 21, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

「？」をつけたキーワードを入力すると、LINEメッセージで概要を返してくれる。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">LINEbotにwikipediaAPIを組み込んでみた。その２<br>？をつけて聞くと説明を返してくれる<a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://t.co/rTZSI99iO4">pic.twitter.com/rTZSI99iO4</a></p>&mdash; yuta kawashima (@y_kawashima_) <a href="https://twitter.com/y_kawashima_/status/1241399282416025606?ref_src=twsrc%5Etfw">March 21, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 準備
まずは @n0bisuke さんが書いた記事を参考に、3.Webhook URLの更新 までは完了させておく。
[1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest](https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90%E3%81%A8%E3%83%8F%E3%83%AD%E3%83%BC%E3%83%AF%E3%83%BC%E3%83%AB%E3%83%89)

# 準備が終わったらやること
基本的に上記記事中のserver.jsの中身を少しだけいじります。

## Wikipedia API
http://wikipedia.simpleapi.net/
この中の「SimpleAPI WikipediaAPI」を使いました。
※ 利用上の注意はよく読みご利用ください。
### サンプル
keywordに「カレー」と渡してあげた場合
http://wikipedia.simpleapi.net/api?keyword=%E3%82%AB%E3%83%AC%E3%83%BC&output=xml

あとは、LINE上で入力した内容をkeywordに渡してあげて、そこで返ってきたものをLINE上にも返信してあげれば良さそう。

## server.jsを変更していく
### 1. require('axios') 
WikipediaのAPIを使うので、`const axios = require('axios'); `を追加。
![スクリーンショット 2020-03-22 01.52.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121887/49ee7afb-5d06-ac4a-0c27-c84e8dfb2425.png)
また、`$ npm i axios` でaxiosのインストールもお忘れなく。

### 2. unction handleEvent(event) { ... } の中身の変更
wikipediaのAPIはこんな内容を返してくれます。
![スクリーンショット 2020-03-22 01.57.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121887/3c0cbc21-83c6-84c7-d117-7a3d918ddec6.png)
bodyがサクッと見たい場合や、しっかりリンクに飛んでwikiページから見たい場合もあると思ったので、今回下記のルールでLINE上に返ってくる内容を分けることにしました。

- キーワードに「？」をつけたとき　→　bodyを表示する
- キーワードだけのとき　　　　　　→　urlを表示する


なので、
「？」がある場合の記述は下記。

``` a.js
if(event.message.text.indexOf('？') > -1){
  // ？を含んでいる場合にはwikiで検索したものを出して、含んでない場合はurlを返す
    var str = event.message.text;
    var result = str.split( '？' ).join( '' ); //？を取り除く処理
    mes = result + 'の説明：'; //wikiのbodyの前の一言
    getBody(event.source.userId,result); //wiki APIで取得できたらプッシュメッセージ
}

```
？が付いたままkeywordに渡してしまうとよくないので、`str.split( '？' ).join( '' )` で？を取り除いているところは少しポイント。
※ getBody の説明は後ほど。

キーワードだけのときの記述は下記。

``` b.js
else{
    var result = event.message.text;
    mes = result + 'のURL：'; //wikiのurlの前の一言
    getUrl(event.source.userId,result); //wiki APIで取得できたらプッシュメッセージ
  }

```
※ getUrlの説明は後ほど。

### 3. getBodyとgetUrl
ポイント

- wikipedia.simpleapiにkeywordに渡してあげるときは、encodeURIComponentで変換する
- outputは扱いやすいようにjsonにする（ `&output=json`）
- このAPIは複数の候補を返してくる為、一番はじめに出力されたものを取得することにする（`item[0]`）
    - 例：keywordが「トマト」の場合、itemの中身は「トマト缶」「トマトピューレ」など複数の似たキーワードでの結果が入ってきている。

``` getBody.js
const getBody = async (userId,word) => {
    const res = await axios.get('http://wikipedia.simpleapi.net/api?keyword='+ encodeURIComponent(word) + '&output=json');
    const item = res.data;
    // console.log(item); 

    await client.pushMessage(userId, {
        type: 'text',
        text: item[0].body,
    });
}
```

``` getUrl.js
const getUrl = async (userId,word) => {
    const res = await axios.get('http://wikipedia.simpleapi.net/api?keyword='+ encodeURIComponent(word) + '&output=json');
    const item = res.data;
    // console.log(item); 
    await client.pushMessage(userId, {
        type: 'text',
        text: item[0].url,
    });
}
```
## 全コード
``` server.js
'use strict';

const express = require('express');
const line = require('@line/bot-sdk');
const PORT = process.env.PORT || 3000;
// 追加
const axios = require('axios');

const config = {
    channelSecret: '作成したBOTのチャンネルシークレット',
    channelAccessToken: '作成したBOTのチャンネルアクセストークン'
};

const app = express();

app.get('/', (req, res) => res.send('Hello LINE BOT!(GET)')); //ブラウザ確認用(無くても問題ない)
app.post('/webhook', line.middleware(config), (req, res) => {
    
    //ここのif文はdeveloper consoleの"接続確認"用なので後で削除して問題ないです。
    if(req.body.events[0].replyToken === '00000000000000000000000000000000' && req.body.events[1].replyToken === 'ffffffffffffffffffffffffffffffff'){
        res.send('Hello LINE BOT!(POST)');
        console.log('疎通確認用');
        return; 
    }

    Promise
      .all(req.body.events.map(handleEvent))
      .then((result) => res.json(result));
});

const client = new line.Client(config);

function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  let mes = ''
// console.log(event.message.text);
    if(event.message.text.indexOf('？') > -1){
        // ？を含んでいる場合にはwikiで検索したものを出して、含んでない場合はurlを返す
    var str = event.message.text;
    var result = str.split( '？' ).join( '' ); //？を取り除く処理
    mes = result + 'の説明：'; //wikiのbodyの前の一言
    getBody(event.source.userId,result); //wiki APIで取得できたらプッシュメッセージ

  }else{
    var result = event.message.text;
    mes = result + 'のURL：'; //wikiのurlの前の一言
    getUrl(event.source.userId,result); //wiki APIで取得できたらプッシュメッセージ
  }

  return client.replyMessage(event.replyToken, {
    type: 'text',
    text : mes 
});
}

const getBody = async (userId,word) => {
    const res = await axios.get('http://wikipedia.simpleapi.net/api?keyword='+ encodeURIComponent(word) + '&output=json');
    const item = res.data;
    // console.log(item); 

    await client.pushMessage(userId, {
        type: 'text',
        text: item[0].body,
    });
}
const getUrl = async (userId,word) => {
    const res = await axios.get('http://wikipedia.simpleapi.net/api?keyword='+ encodeURIComponent(word) + '&output=json');
    const item = res.data;
    // console.log(item); 
    await client.pushMessage(userId, {
        type: 'text',
        text: item[0].url,
    });
}

app.listen(PORT);
console.log(`Server running at ${PORT}`);

```


## 終わりに
検索のログがトークログの形で残るので「あのとき調べたアレなんだっけ」という時にも遡りやすいので、普通にググるのとはまた違ってモノとしては結構便利だなと思いました。

実装観点でいくと、simpleAPIはありそうなkeywordでもまあまあ結果が返ってこない時があるので、その場合の処理の分岐は入れたほうがよかったなと思ってはいます。。