Contents

GolangでLine APIをいじくるよ

GolangでLine APIをいじくる

GolangLine APIを用いたボット作成をしてみます。

説明すること・しないこと

この記事ではLine Messaging APIを使って、どんなメッセージを送信できるかを説明します。

どうすればボット作成環境を構築するかなどは説明しません。参考リンクなど確認ください。

簡単な説明

下の図のLineBotServerの部分を作り込みます:

Line Developerに登録する

お金をかけずにLINEのMessaging APIの投稿(push)と返信(replay)を試してみる。 | ポンコツエンジニアのごじゃっぺ開発日記。に書いてある通りに進めます。

とりあえず動作させてみます

送信できるメッセージの種類ごとにテストしてみます。

テキストメッセージ

“text”とメッセージ送信したら、”text”と返信するようにしてみました。

https://farm8.staticflickr.com/7891/46350633365_4e30224e64.jpg

画像メッセージ

“image”とメッセージ送信したら、画像を投稿するようにしてみました。

https://farm8.staticflickr.com/7819/33389330058_05399428bd.jpg

スタンプメッセージ

“sticker”とメッセージ送信したら、スタンプを投稿するようにしてみました。送信できるステッカーはLine Botで送信できるSticker一覧 (PDF)から確認できます:

https://farm8.staticflickr.com/7807/40300515403_5993c84e2a.jpg

位置情報メッセージ

“location”とメッセージ送信したら、地図情報を投稿するようにしてみました:

https://farm8.staticflickr.com/7918/46350633335_f2e7ecda53.jpg

テンプレートメッセージ

画像やボタンなどを組み合わせたメッセージです。

ボタンテンプレート

こんな感じのメッセージになります:

https://farm8.staticflickr.com/7808/33389330098_48880e1512.jpg

確認テンプレート

確認を行うダイアログ?的なメッセージになります:

https://farm8.staticflickr.com/7880/40300515423_e471e9de20.jpg

カルーセルテンプレート

横方向にテンプレートメッセージを並べたメッセージです。こんな感じになります:

https://farm8.staticflickr.com/7870/47213297182_fab28aa76e.jpg

Flexメッセージ

テンプレートメッセージのレイアウトを自由に調整できるみたいなのですが、サンプルしか触っていないため、ちょっとよくわかっていないです。こんな感じになりました:

https://farm8.staticflickr.com/7912/40300515343_910467fd1e.jpg

もっとレイアウトにこったサンプルがあればいいのですが。。。

クイックレスポンスメッセージ

メッセージ送信と同時に、簡単な選択肢を提示して、選択してもらうことができるようです:

https://farm8.staticflickr.com/7887/46350633325_0398b4f65c.jpg

位置情報の送信、カメラ起動、カメラロールから画像選択などもできるみたい。上の例だと、右端のリンクをクリックすると、位置情報の送信画面になります。

その他 (ボタンをクリックするとできること)

テンプレートメッセージやFlexメッセージでボタンを配置してできることは、以下のようです。

Postback action

Botのcallback URLに対して、データをPOSTリクエストで送信するようです。

Message action

選択したボタンに割り当てたメッセージをLine上で送信するみたいです。

URI action

選択したボタンに割り当てたURLをLineのブラウザで開くようです。

Datetime picker action

日付選択用の画面が出てきます。

https://farm8.staticflickr.com/7897/33389330108_8d940922b1.jpg

Camera action

クイックレスポンスの時にのみ利用できるアクションのようです。カメラが起動します。

Camera roll action

クイックレスポンスの時にのみ利用できるアクションのようです。カメラロールが開いて、画像を選択できるようです。

Location action

クイックレスポンスの時にのみ利用できるアクションのようです。位置情報の画面が出てくるようです。

コード

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
package main

import (
        "log"
        "net/http"
        "os"
        "time"

        "github.com/jinzhu/gorm"
        _ "github.com/jinzhu/gorm/dialects/mysql"
        "github.com/line/line-bot-sdk-go/linebot"
)

const (
        userStatusAvailable    string = "available"
        userStatusNotAvailable string = "not_available"
)

type user struct {
        Id         string `gorm:"primary_key"`
        IdType     string
        Timestamp  time.Time `gorm:"not null;type:datetime"`
        ReplyToken string
        Status     string
}

func gormConnect() *gorm.DB {
        DBMS := "mysql"
        USER := "root"
        PASS := "Holiday88"
        PROTOCOL := "tcp(192.168.10.200:3307)"
        DBNAME := "LineBot"

        CONNECT := USER + ":" + PASS + "@" + PROTOCOL + "/" + DBNAME + "?parseTime=true&loc=Asia%2FTokyo"
        db, err := gorm.Open(DBMS, CONNECT)

        if err != nil {
                log.Fatal(err.Error())
        }
        return db
}

func main() {
        bot, err := linebot.New(
                os.Getenv("CHANNEL_SECRET"),
                os.Getenv("CHANNEL_TOKEN"),
        )
        if err != nil {
                log.Fatal(err)
        }

        // Setup HTTP Server for receiving requests from LINE platform
        http.HandleFunc("/callback", func(w http.ResponseWriter, req *http.Request) {
                events, err := bot.ParseRequest(req)
                if err != nil {
                        if err == linebot.ErrInvalidSignature {
                                w.WriteHeader(400)
                        } else {
                                w.WriteHeader(500)
                        }
                        return
                }

                for _, event := range events {
                        switch event.Type {
                        case linebot.EventTypeFollow:
                                // db instance
                                db := gormConnect()
                                defer db.Close()

                                userData := user{Id: event.Source.UserID,
                                        IdType:     string(event.Source.Type),
                                        Timestamp:  event.Timestamp,
                                        ReplyToken: event.ReplyToken,
                                        Status:     userStatusAvailable,
                                }
                                err := db.Where(user{Id: event.Source.UserID}).Assign(&userData).FirstOrCreate(&user{})
                                log.Println(err)

                        case linebot.EventTypeUnfollow:
                                log.Println("Unfollow Event: " + event.Source.UserID)
                                log.Println(event)

                                // db instance
                                db := gormConnect()
                                defer db.Close()

                                userData := user{Id: event.Source.UserID,
                                        IdType:     string(event.Source.Type),
                                        Timestamp:  event.Timestamp,
                                        ReplyToken: event.ReplyToken,
                                        Status:     userStatusNotAvailable,
                                }

                                err := db.Where(user{Id: event.Source.UserID}).Assign(&userData).FirstOrCreate(&user{})
                                log.Println(err)

                        case linebot.EventTypeMessage:
                                log.Println(event)
                                switch message := event.Message.(type) {
                                case *linebot.TextMessage:
                                        switch message.Text {
                                        case "text":
                                                resp := linebot.NewTextMessage(message.Text)

                                                _, err := bot.ReplyMessage(event.ReplyToken, resp).Do()
                                                if err != nil {
                                                        log.Print(err)
                                                }
                                        case "sticker":
                                                resp := linebot.NewStickerMessage("3", "230")

                                                _, err = bot.ReplyMessage(event.ReplyToken, resp).Do()
                                                if err != nil {
                                                        log.Print(err)
                                                }
                                        case "location":
                                                resp := linebot.NewLocationMessage("現在地", "宮城県多賀城市", 38.297807, 141.031)

                                                _, err = bot.ReplyMessage(event.ReplyToken, resp).Do()
                                                if err != nil {
                                                        log.Print(err)
                                                }
                                        case "image":
                                                resp := linebot.NewImageMessage("https://farm5.staticflickr.com/4849/45718165635_328355a940_m.jpg", "https://farm5.staticflickr.com/4849/45718165635_328355a940_m.jpg")

                                                _, err = bot.ReplyMessage(event.ReplyToken, resp).Do()
                                                if err != nil {
                                                        log.Print(err)
                                                }
                                        case "buttontemplate":
                                                resp := linebot.NewTemplateMessage(
                                                        "this is a buttons template",
                                                        linebot.NewButtonsTemplate(
                                                                "https://farm5.staticflickr.com/4849/45718165635_328355a940_m.jpg",
                                                                "Menu",
                                                                "Please select",
                                                                linebot.NewPostbackAction("Buy", "action=buy&itemid=123", "", "displayText"),
                                                                linebot.NewPostbackAction("Buy", "action=buy&itemid=123", "text", ""),
                                                                linebot.NewURIAction("View detail", "http://example.com/page/123"),
                                                        ),
                                                )

                                                _, err = bot.ReplyMessage(event.ReplyToken, resp).Do()
                                                if err != nil {
                                                        log.Print(err)
                                                }
                                        case "datetimepicker":
                                                resp := linebot.NewTemplateMessage(
                                                        "this is a buttons template",
                                                        linebot.NewButtonsTemplate(
                                                                "https://farm5.staticflickr.com/4849/45718165635_328355a940_m.jpg",
                                                                "Menu",
                                                                "Please select a date,  time or datetime",
                                                                linebot.NewDatetimePickerAction("Date", "action=sel&only=date", "date", "2017-09-01", "2017-09-03", ""),
                                                                linebot.NewDatetimePickerAction("Time", "action=sel&only=time", "time", "", "23:59", "00:00"),
                                                                linebot.NewDatetimePickerAction("DateTime", "action=sel", "datetime", "2017-09-01T12:00", "", ""),
                                                        ),
                                                )

                                                _, err = bot.ReplyMessage(event.ReplyToken, resp).Do()
                                                if err != nil {
                                                        log.Print(err)
                                                }
                                        case "confirm":
                                                resp := linebot.NewTemplateMessage(
                                                        "this is a confirm template",
                                                        linebot.NewConfirmTemplate(
                                                                "Are you sure?",
                                                                linebot.NewMessageAction("Yes", "yes"),
                                                                linebot.NewMessageAction("No", "no"),
                                                        ),
                                                )

                                                _, err = bot.ReplyMessage(event.ReplyToken, resp).Do()
                                                if err != nil {
                                                        log.Print(err)
                                                }
                                        case "carousel":
                                                resp := linebot.NewTemplateMessage(
                                                        "this is a carousel template with imageAspectRatio,  imageSize and imageBackgroundColor",
                                                        linebot.NewCarouselTemplate(
                                                                linebot.NewCarouselColumn(
                                                                        "https://farm5.staticflickr.com/4849/45718165635_328355a940_m.jpg",
                                                                        "this is menu",
                                                                        "description",
                                                                        linebot.NewPostbackAction("Buy", "action=buy&itemid=111", "", ""),
                                                                        linebot.NewPostbackAction("Add to cart", "action=add&itemid=111", "", ""),
                                                                        linebot.NewURIAction("View detail", "http://example.com/page/111"),
                                                                ).WithImageOptions("#FFFFFF"),
                                                                linebot.NewCarouselColumn(
                                                                        "https://farm5.staticflickr.com/4849/45718165635_328355a940_m.jpg",
                                                                        "this is menu",
                                                                        "description",
                                                                        linebot.NewPostbackAction("Buy", "action=buy&itemid=111", "", ""),
                                                                        linebot.NewPostbackAction("Add to cart", "action=add&itemid=111", "", ""),
                                                                        linebot.NewURIAction("View detail", "http://example.com/page/111"),
                                                                ).WithImageOptions("#FFFFFF"),
                                                        ).WithImageOptions("rectangle", "cover"),
                                                )
                                                _, err = bot.ReplyMessage(event.ReplyToken, resp).Do()
                                                if err != nil {
                                                        log.Print(err)
                                                }
                                        case "flex":
                                                resp := linebot.NewFlexMessage(
                                                        "this is a flex message",
                                                        &linebot.BubbleContainer{
                                                                Type: linebot.FlexContainerTypeBubble,
                                                                Body: &linebot.BoxComponent{
                                                                        Type:   linebot.FlexComponentTypeBox,
                                                                        Layout: linebot.FlexBoxLayoutTypeVertical,
                                                                        Contents: []linebot.FlexComponent{
                                                                                &linebot.TextComponent{
                                                                                        Type: linebot.FlexComponentTypeText,
                                                                                        Text: "hello",
                                                                                },
                                                                                &linebot.TextComponent{
                                                                                        Type: linebot.FlexComponentTypeText,
                                                                                        Text: "world",
                                                                                },
                                                                        },
                                                                },
                                                        },
                                                )

                                                _, err = bot.ReplyMessage(event.ReplyToken, resp).Do()
                                                if err != nil {
                                                        log.Print(err)
                                                }
                                        case "quickresponse":
                                                resp := linebot.NewTextMessage(
                                                        "Select your favorite food category or send me your location!",
                                                ).WithQuickReplies(
                                                        linebot.NewQuickReplyItems(
                                                                linebot.NewQuickReplyButton("https://example.com/sushi.png", linebot.NewMessageAction("Sushi", "Sushi")),
                                                                linebot.NewQuickReplyButton("https://example.com/tempura.png", linebot.NewMessageAction("Tempura", "Tempura")),
                                                                linebot.NewQuickReplyButton("", linebot.NewLocationAction("Send location")),
                                                        ),
                                                )

                                                _, err = bot.ReplyMessage(event.ReplyToken, resp).Do()
                                                if err != nil {
                                                        log.Print(err)
                                                }
                                        }
                                }
                        }
                }
        })

        if err := http.ListenAndServe(":"+os.Getenv("PORT"), nil); err != nil {
                log.Fatal(err)
        }
}

参考