LINE Botの開発の際のエラーをいい感じに出したい 


Node.jsでLINE Botを作る時は以下のSDKを使うのが一般的になってると思います。

https://github.com/line/line-bot-sdk-nodejs 

こちらのSDKでLINE Bot開発をしている際の話になります。

## LINE Botのエラーどこ見れば良いのか分かりにくい

LINE Botのエラーといっても色々ありますが、APIリクエストの際のHTTPエラー周りがメインになります。

以下のようにログが色々と出て、どこが肝心のエラーメッセージなのか分かりにくいですよね。

> ![](https://i.gyazo.com/6ea12a2393d8fd45c5cd66642dea2619.gif)

これを見やすくしたいと思います。

## まずはエラーを出すコード

以下のLINE Botはユーザーの発言をオウム返ししますが、一つの発言に対して複数返してくるウザい感じのBotです。

イメージ
> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/ca59f0b4-38fa-9897-8df0-14ed851731f5.png" width="400px" >

**LINE Messaging APIの仕様上5つまでしか返答できません** が、以下のコードだと6つのメッセージを返そうとしていてエラーになります。

```app.js
'use strict';

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

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

const app = express();

app.get('/', (req, res) => res.send('Hello LINE BOT!(GET)')); //ブラウザ確認用(無くても問題ない)
app.post('/webhook', line.middleware(config), (req, res) => {
    console.log(req.body.events);

    Promise
    .all(req.body.events.map(handleEvent))
    .then((result) => res.json(result))
    .catch((err) => {
      console.error(err);
      res.status(500).end();
    });
});

const client = new line.Client(config);

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

  const message = {
    type: 'text',
    text: event.message.text //実際に返信の言葉を入れる箇所
  };
  
  //APIの仕様的にエラーがでる箇所 6つ指定している
  return client.replyMessage(event.replyToken, [message, message, message, message, message, message]);
}

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

プログラムを実行して、ユーザーがBOTに話しかけるとエラーが起きてエラーオブジェクトの情報がターミナルにたくさん出てきます。

> こんな感じ
> ![](https://i.gyazo.com/6ea12a2393d8fd45c5cd66642dea2619.gif)

ちなみにここが該当箇所になります。

```js
Promise
      .all(req.body.events.map(handleEvent))
      .then((result) => res.json(result))
      .catch((err) => {
 	    console.error(err); //←ココ
        res.status(500).end();
      });
```


参考として、[こちらの記事](https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d#2-nodejs%E3%81%A7bot%E9%96%8B%E7%99%BA)のコードを使っています。（以前は記事内に`.catch`部分がなかったので更新しました。）

## err.originalError.response.dataでメッセージだけいい感じに出せた

`console.error(err.originalError.response.data);`という指定にすることでエラーがスッキリします。

```js
Promise
      .all(req.body.events.map(handleEvent))
      .then((result) => res.json(result))
      .catch((err) => {
 	     console.error(err.originalError.response.data); //←ココ
        res.status(500).end();
      });
```

同じようにエラーを出してみると出力が以下のようになりました。

> ![](https://i.gyazo.com/84942195114176473446410bc7aa21dd.png)

```bash
{
  message: 'The request body has 1 error(s)',
  details: [ { message: 'Size must be between 1 and 5', property: 'messages' } ]
}
```

この`Size must be between 1 and 5`が仕様的に1個〜5個のメッセージしか返せないというエラー内容になってきます。今回はなぜでエラーが起きてるか把握しながらやってましたが、意図しないエラーが起きた時にエラーメッセージがすぐに分かるのは地味に嬉しいです。

## まとめ

逆にヘッダー部分がどうなってるかなどの詳細は表示されなくなるので注意が必要ですが、取り急ぎAPIリクエストでのエラーメッセージを見たい時には良さそうです。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">LINE Bot SDKからのリクエストはaxiosを使ってるっぽい<br><br>console.error(<a href="https://t.co/pyNucjVBeF">https://t.co/pyNucjVBeF</a>);でエラーとれるぽい<br><br>&gt; <a href="https://t.co/1Y50iCZdT1">https://t.co/1Y50iCZdT1</a><br>&gt; <a href="https://t.co/MwkQAJS9QD">https://t.co/MwkQAJS9QD</a><a href="https://twitter.com/hashtag/linedc?src=hash&amp;ref_src=twsrc%5Etfw">#linedc</a> <a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a></p>&mdash; 菅原のびすけ （プロトアウト9期募集中) (@n0bisuke) <a href="https://twitter.com/n0bisuke/status/1664922891211735040?ref_src=twsrc%5Etfw">June 3, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 補足

以下の記事にこの辺の話が載ってました。参考にさせていただきました。

参考: https://dev.classmethod.jp/articles/line-bot-sdk-nodejs-error-messages/

このLINE Bot SDKのAPIリクエストはaxiosに依存しているみたいです。

axiosを利用する他のコードでも同じような指定ができるかもしれません。

https://github.com/axios/axios