昨日作ったchatbotがあのままだと全く実用性がないので、もうちょっとサンプルっぽくしました
昨日作ったもの
https://qiita.com/usk81/items/bfd15ec3c5ecc23d0b8f
Twistに関しては昨日作ったものの記事を参考にしてください
成果物
コメントしたものをそのまま返すようにしました
Page: https://github.com/usk81/twistbot
Release: https://github.com/usk81/twistbot/releases/tag/v0.0.1-alpha2
Request Body
Request Bodyはx-www-form-urlencoded
で送られているようです。
どうせなので、Structureにおこしてみました。
というか、Developerページと差異があってほぼここの解析に時間使ってました。
StructureへのデコードはGorilla
のSchema
を使用しました。
https://github.com/gorilla/schema
今回は対応しませんでしたが、リクエストの中にurl_ttl
と url_callback
というものがあります。
url_ttl
にはタイムスタンプ
url_callback
にはURLが格納されています。
リクエストの返却に時間がかかる場合は、一度202で空リクエストを返して、url_ttl
で設定されている制限時間内にurl_callback
にリクエストを返せばいいそうです。
type TwistOutgoingRequest struct {
EventType string `schema:"event_type"`
WorkspaceID int `schema:"workspace_id"`
Content string `schema:"content"`
UserID int `schema:"user_id"`
UserName string `schema:"user_name"`
URLCallback string `schema:"url_callback"`
URLTTL int `schema:"url_ttl"`
MessageID int `schema:"message_id"`
ThreadID int `schema:"thread_id"`
ThreadTitle string `schema:"thread_title"`
ChannelID int `schema:"channel_id"`
ChannelName string `schema:"channel_name"`
CommentID int `schema:"comment_id"`
ConversationID int `schema:"conversation_id"`
ConversationTitle string `schema:"conversation_title"`
VerifyToken string `schema:"verify_token"`
}
Handler
修正前
func botHandler(w http.ResponseWriter, r *http.Request) {
if r == nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("can not get request"))
}
defer r.Body.Close()
bs, _ := ioutil.ReadAll(r.Body)
w.Write([]byte(fmt.Sprintf("header: %s, body: %s", r.Header.Get("Content-Type"), string(bs))))
}
修正後
デバッグも兼ねて、ログも仕込んでみました。
サーバのログをミドルウェア層をzapで作ったので、ソフトウェア層も揃えました。
https://github.com/uber-go/zap
message_idとかが返ってきてたので、APIでmessage取得しないといけないのかと思ってましたが、contentに平文で入ってました。
func botHandler(w http.ResponseWriter, r *http.Request) {
lg, _ := zap.NewProduction()
defer lg.Sync()
if r == nil {
lg.Error("can not get request")
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("can not get request"))
}
if err := r.ParseForm(); err != nil {
lg.Warn(fmt.Sprintf("failed to parse request %s", err.Error()))
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("request is invalid"))
}
var req TwistOutgoingRequest
if err := decoder.Decode(&req, r.PostForm); err != nil {
lg.Error(fmt.Sprintf("fail to decode parsed request %s : %#v", err.Error(), r.PostForm))
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
}
w.Write([]byte(req.Content))
}