LINE Botの作り方と作ってみた時にマジかと思ったことと作るときに使ってほしいサンプルと・・・っていうたくさんの話

# 初めに
この投稿は以下の構成となっております

* 作り方
* マジかと思ったこと
→作ってて僕がまじかよと思ったこと
ここはこうしてほしかったなーと思ったこと
* LINE Bot作るときに使ってほしいサンプル
→1から作るの面倒だからある程度まで作ってあるASPのRestAPIとService

#作り方

1. ボットアカウント作成  
  1. [LINE BUSINESS CENTER](https://business.line.me/ja/)にログイン  
ログインは自分のLINEアカウントで入れます  
LINEのパスワード思い出すのに小一時間かかった・・・  
  2. アカウントリストからビジネスアカウント作成
  3. MessagingAPIを始めるを選択
  4. アカウントを作成  
  名前を付けたり画像を選択したり  
業種は自分のじゃなくてそのアカウント(Bot)についてだからね  
![がぞー](https://qiita-image-store.s3.amazonaws.com/0/195499/dff677d6-3f25-5f75-cb21-771490d49c26.png)  
こういうのができればOK!
1. ボットの設定をする
  1. できたボットのLINE@MANAGERをクリック
  1. アカウント設定→Bot設定からAPIを利用するをクリック  
  この時トークとか使えなくなりますよ！って警告が出るけど、これはBot用のアカウントがってことで、普段自分が使ってるアカウントのことではないからねｗ  
僕も一番最初はビビって確認ボタン押せなかったｗｗ
  1. Webhook送信を利用するにチェック(重要！)
![がぞー](https://qiita-image-store.s3.amazonaws.com/0/195499/aec59dd0-a956-d566-31f9-99ca4cf81816.png)  
  自動応答メッセージを利用しないにチェックしててもWebhook先APIからリプライは送れます  
  メニューのメッセージに設定できる場所があって、そこにあるメッセージを利用するかどうかっていうのです  
1. ボットの設定をするその２
  1. Botの設定のとこにある「LINE Developersで設定する」を選択  
  ![がぞー](https://qiita-image-store.s3.amazonaws.com/0/195499/6c1ea94e-bb47-adff-2a25-b888bf0b819d.png)  
  こういうのが出て来ると思う
  1. ISSUEをクリックしてチャンネルアクセストークンを取得
  こいつはBotを一意に識別するトークン  
  これはWebhook先のAPIからリプライを飛ばすときとか、画像や動画が通知された時にそのバイナリデータを取得するときに使ったりする
  1. Webhook URLに作ったAPIのURLを追加
  APIが完成したらここに指定しよう！

完成！！！！

え？API側は？って人はリファレンスを見よう！日本語だしどちゃくそ丁寧！
僕がBot作ったときはC#、ASPで作った！
別にリクエストが受け取れるなら何でもいい！！！！

リクエストは [こんな感じ](https://devdocs.line.me/ja/#webhooks)
通知は全部一つのAPIにでかいリクエストが送られてきて、その中のtypeを見て何のイベントか判断します
テキストが送られてきた時も、画像を送るときも、友達追加したときも、ブロックしたときもAPIは全部一つ！
ただ、eventオブジェクト配下のtypeが違ってて、リクエスト内でそのtypeで処理を分岐させます  

画像や動画のバイナリデータは[ここから](https://devdocs.line.me/ja/#content)取る
イベントタイプがmessageの時でさらにmessageオブジェクト配下のtypeがimageやvideoだった時にContentに対してAPIを投げるとバイナリデータが取れます  

リプライを返す時は[ここ！](https://devdocs.line.me/ja/#reply-message)
一度に返せるリプライは最大5つまで（爆撃はできないのね・・・やろうと思ったらPush通知のほうが必要かな？）

プッシュ通知は[ここ](https://devdocs.line.me/ja/#push-message)
だけどお金がかかる！
プッシュ通知がしたかったら有料！
でも逆にプッシュ通知しないなら無料で作れる！！！！

  
# マジかと思ったこと  
## ユーザから受け取った画像をそのままリプライで返せない  
マジか～～～～～～～  
僕がLINE Botで作ったのはLINEから受け取った画像からAzureのCognitiveServiceを使って顔情報を取得、そのまま画像を加工してリプライを返す・・・というものだった
ユーザから通知を受けとった際に、イベント種別より画像、動画、音声等々のバイナリデータをContentから取得します
で、CognitiveSerciceに渡すのもバイナリデータ、BitmapとかGraphicsで画像を加工するのもバイナリデータ・・・
なのにリプライを返す時にはバイナリじゃなくURL！
いったんどこかに保存しないといけないし、それが外部から見える位置にないといけない・・・
まぁ画像が返ってくるAPI作っておけば画像自体は見えなくてもいいんだけど
仕方ないのかなぁ・・・

## Postback送信時にメッセージ用のリクエストも飛んでくる
マジか～～～～～～～～～～～～～～  
これ何かっていうとConfirmやCarousel等をリプライで返すとユーザにボタンを押してもらえるテンプレートが通知できます
このボタンを押したときにpostbackでデータを受け取れるんだけど、ボタンを押したときにユーザに発現させるテキストについても
APIが動いちゃって2つリクエストを受け取ることになる・・・
だからテキストで反応するBotを作るときは要注意

## LINEから飛んでくるリクエストを確認するためにAPIを公開する必要がある
まじか～～～～～～～～～～～～～～！！！！！！！！！  
まぁCurlコマンドで確認すれば済む話なんですけどね・・・
LINEからWebhookでAPI飛ばしてもらおうと思うと
* 外部サーバから見えるAPIである必要がある
* HTTPSである必要がある
っていう・・・
Curlも一回作っちゃえばいいんだけど・・・
僕はAzureにWebApp乗っけて確認してました
発行から選んでポチーでAPIが公開できるからかーんたん♪
でもおかげで使用料1万～2万円くらいが簡単に飛んできました・・・

# LINE Bot作るときに使ってほしいサンプル
作りました
https://github.com/ShassBeleth/LineBotTemplate
MasterブランチPullしてください

## 開発環境
Visual Studio 2017
C# 7.0

## 実装
* Webhookを受け取るController
* 各イベント種別毎に使えるオブジェクトや変数を制限してメソッド作成
* リプライ用Service、プロフィール取得用Service、Content取得用Service
* リプライのサンプル、Confirm、Carousel、Buttonのサンプル

## 使い方
* ServiceとModelの中は基本的に触らなくていいはず
* Controllerクラス内のTODOを検索するとチャンネルアクセストークンを入れる場所があるからそこにBusinessCenterからとってきたトークンを突っ込む
* APIの公開とBotのWebhookに設定  

これでとりあえず動くはず
で、あとはもっかいControllerのTODOで検索すると〇〇の時はここに実装　ってのがあるからサンプル見ながら好きなように実装する！

```C#:WebhookController.cs
/// <summary>
/// チャンネルアクセストークンの取得
/// </summary>
/// <returns>チャンネルアクセストークン</returns>
private string GetChannelAccessToken() {

  string token = "";

  // TODO ここに実装方法を記述
  // 例：app.configから取得　定数クラスから取得等

  return token;

}
```

これね

で、URLとマッピングしてるPostメソッドは基本的に触らない
リクエストの内容毎に分岐してるから
分岐した先にあるメソッドではそのイベントで使えるパラメータだけが引数として渡されてる

``` C#:WebhookController.cs
/// <summary>
/// 追加時イベント
/// 友達登録、ブロック解除時、グループ追加時、トークルーム追加時
/// </summary>
/// <param name="channelAccessToken">チャンネルアクセストークン</param>
/// <param name="replyToken">リプライトークン</param>
/// <param name="timestamp">Webhook受信日時</param>
/// <param name="sourceType">イベント送信元種別</param>
/// <param name="sourceId">イベント送信元ID</param>
private async Task ExecuteJoinEvent(
  string channelAccessToken ,
  string replyToken ,
  string timestamp ,
  RequestOfWebhook.Event.Source.SourceType sourceType ,
  string sourceId
) {

  Trace.TraceInformation( "Join Event Start" );
  Trace.TraceInformation( "Channel Access Token is : " + channelAccessToken );
  Trace.TraceInformation( "Reply Token is : " + replyToken );
  Trace.TraceInformation( "Timestamp is : " + timestamp );
  Trace.TraceInformation( "Source Type is : " + sourceType );
  Trace.TraceInformation( "Source Id is : " + sourceId );

  // TODO ここにイベント内容を記載
  // 以下サンプル
  await this.ReplyTextMessageSampleEvent( channelAccessToken , replyToken , "追加されました" );

  Trace.TraceInformation( "Join Event End" );

}
```
例えばこれは友達登録とかしたときに飛んでくる追加イベント
ここでリクエストパラメータとして使いたいのはリプライを飛ばすためのリプライトークン`replyToken`とどこに追加されたかのイベント送信元種別`sourcetype`とイベント送信元ID`sourceId`
こういうのを制限してLINE Botつくろーって時に来もしないパラメータ見る必要を極力少なくしてみました

リプライを飛ばすときはReplyMessageServiceを使う

``` C#:WebhookController.cs
/// <summary>
/// テキストサンプル
/// </summary>
/// <param name="replyToken">リプライトークン</param>
/// <param name="channelAccessToken">チャンネルアクセストークン</param>
/// <param name="text">テキスト</param>
/// <returns></returns>
private async Task ReplyTextMessageSampleEvent(
  string replyToken ,
  string channelAccessToken ,
  string text
) => await new ReplyMessageService( replyToken , channelAccessToken )
  .AddTextMessage( text )
  .Send();

```
こんな感じにServiceクラスをnewして、それに送るリプライ分Addメソッドつないで、最後にSendメソッドを呼ぶ
こんだけ！


## 今後
一通りAPIを網羅してテンプレートとして使えるものにしたいね
入力チェックとかもしてないし
後、リプライ送るときにAddせずにSendメソッドが呼べないようにしたい
他にはー・・・カラムを追加するときとかルール無視でModelの配列渡したりとかできるからできないようにしたいね
改良はまだまだこれから
またLINE Bot触りたくなったら続きやる


# 最後に
Qiita初投稿でつたない文章だと思いますが、最後までご覧いただきありがとうございました
LINE Bot作るのすごい簡単だったのでみんなも是非作ってみてほしい！