22 KiB
+++ title = "GolangでLine APIをいじくるよ" date = 2019-03-03T19:12:22+08:00 description = "GolangでLine APIを利用してみましたよ。" tags = ["Golang"] categories = ["プログラミング"] author = "kazu634" images = ["ogp/2019-02-23-line-sdk-go.webp"] +++
GolangでLine APIをいじくる
Golang
でLine
APIを用いたボット作成をしてみます。
説明すること・しないこと
この記事ではLine Messaging APIを使って、どんなメッセージを送信できるかを説明します。
どうすればボット作成環境を構築するかなどは説明しません。参考リンクなど確認ください。
簡単な説明
下の図のLineBotServerの部分を作り込みます:
{{}} sequenceDiagram User->>Line: Some Action(s) Line->>LineBotServer: Make HTTP Request alt Bad Request Note over LineBotServer: Do nothing else Proper Request LineBotServer->>LineBotServer: Do something LineBotServer->>Line: Make HTTP Request, using REST API Line->>User: Show some message(s) as Reply end {{< /mermaid >}}
Line Developerに登録する
お金をかけずにLINEのMessaging APIの投稿(push)と返信(replay)を試してみる。 | ポンコツエンジニアのごじゃっぺ開発日記。に書いてある通りに進めます。
とりあえず動作させてみます
送信できるメッセージの種類ごとにテストしてみます。
テキストメッセージ
“text”とメッセージ送信したら、”text”と返信するようにしてみました。
画像メッセージ
“image”とメッセージ送信したら、画像を投稿するようにしてみました。
スタンプメッセージ
“sticker”とメッセージ送信したら、スタンプを投稿するようにしてみました。送信できるステッカーはLine Botで送信できるSticker一覧 (PDF)から確認できます:
位置情報メッセージ
“location”とメッセージ送信したら、地図情報を投稿するようにしてみました:
テンプレートメッセージ
画像やボタンなどを組み合わせたメッセージです。
ボタンテンプレート
こんな感じのメッセージになります:
確認テンプレート
確認を行うダイアログ?的なメッセージになります:
カルーセルテンプレート
横方向にテンプレートメッセージを並べたメッセージです。こんな感じになります:
Flexメッセージ
テンプレートメッセージのレイアウトを自由に調整できるみたいなのですが、サンプルしか触っていないため、ちょっとよくわかっていないです。こんな感じになりました:
もっとレイアウトにこったサンプルがあればいいのですが。。。
クイックレスポンスメッセージ
メッセージ送信と同時に、簡単な選択肢を提示して、選択してもらうことができるようです:
位置情報の送信、カメラ起動、カメラロールから画像選択などもできるみたい。上の例だと、右端のリンクをクリックすると、位置情報の送信画面になります。
その他 (ボタンをクリックするとできること)
テンプレートメッセージやFlexメッセージでボタンを配置してできることは、以下のようです。
Postback action
Botのcallback URLに対して、データをPOSTリクエストで送信するようです。
Message action
選択したボタンに割り当てたメッセージをLine上で送信するみたいです。
URI action
選択したボタンに割り当てたURLをLineのブラウザで開くようです。
Datetime picker action
日付選択用の画面が出てきます。
Camera action
クイックレスポンスの時にのみ利用できるアクションのようです。カメラが起動します。
Camera roll action
クイックレスポンスの時にのみ利用できるアクションのようです。カメラロールが開いて、画像を選択できるようです。
Location action
クイックレスポンスの時にのみ利用できるアクションのようです。位置情報の画面が出てくるようです。
コード
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)
}
}
参考
- お金をかけずにLINEのMessaging APIの投稿(push)と返信(replay)を試してみる。 | ポンコツエンジニアのごじゃっぺ開発日記。
- Line Botで送信できるSticker一覧 (PDF)
- LINE Messaging APIのテンプレートメッセージをまとめてみる | DevelopersIO
- LINE Messaging APIのテンプレートメッセージをまとめてみる(アクションオブジェクト編) | DevelopersIO
- LINE Messaging APIとは?~Flex Messageやクイックリプライ等の新機能追加でより柔軟なメッセージ配信が可能に - Feedmatic Blog
- Using quick replies
- 毎朝 天気を通知する LINE Bot を作ってみました。 - hawk, camphora, avocado and so on..
- 【LINE Botの作り方】Python × Messaging APIでプッシュ通知を行うボットを作ろう | TAKEIHO
- LINE Messaging API を使ってLINEにメッセージ送信/メッセージ返信する - Qiita