ただ一つの文を送る機能の実装
とりあえず、Block Kit云々言う前に、ひとこと物申す機能を実装しようと思います。
先程取得したWebhook URLにBodyにJSON を持ったPOSTを投げればできます。
肝心のJSON データはこんな感じ
{
"username " : "通知上で表示されるユーザ名 ",
"icon_url " : "通知上で表示されるユーザ画像 ", // icon_emoji で指定するとSlack絵文字が使用できます
"text " : "通知内容 "
}
ではこれを送るコードを実装しましょう
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
)
func main() {
slack := "https://投稿先SlackURL"
bodyJSON, err := json.Marshal(map [string ]interface {}{
"username" : "inoriko711" ,
"icon_url" : "https://iconURL" ,
"text" : "テスト" ,
})
if err != nil {
fmt.Println(err)
return
}
resp, err := http.Post(slack, "application/json" , bytes.NewReader(bodyJSON))
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
if _, err := io.Copy(ioutil.Discard, resp.Body); err != nil {
fmt.Println(err)
}
}
go run [ファイル名].go で実行!
…でけた
Block Kitの箇所を準備する
Block Kit Builderで作成されたJSON ですが、思いの外複雑な上、必須パラメータが欠けると問答無用で投稿できなくなります。
(Blockが欠けるとかじゃないです。全て投稿できなくなるんです。)
さらに、私、自慢じゃないですけどtypo が多いです。いちいちJSON のキー名を手打ちするのはしんどいです。
そのため各Block毎に構造体を作成して、その構造体に沿ってさえいれば問題なく投稿できるような仕組みを準備します。
Header部分はこちら
Header画像 該当JSON はこんな感じです。
{
"type ": "header ",
"text ": {
"type ": "plain_text ",
"text ": ":star2:癒しタイム:star2: ",
"emoji ": true
}
}
Headerの要素に関する詳しい説明はこちらReference: Layout blocks | Slack に書かれてあります。
Fieldとしてはtypeとtextが必須、block_idは任意。型としてはtypeとblock_idはstring、textはオブジェクトです。
そのためGoコードとしては以下の型を準備します。
type HeaderBlock struct {
Type string `json:"type"`
Text interface {} `json:"text"`
BlockID string `json:"block_id,omitempty"`
}
`json :"キー名"で入力しておくことで、Go側でよしなにしてくれます。便利。
またomitemptyを付与しておくことでコード上で何も指定されなかった(nil の)際、JSON に直すときにキー毎省いてくれます。とっても便利。
先程textの値の型はオブジェクトだって申し上げた舌の根も乾かぬうちにアレですが、よくよく読むと値はTextObject しか持たないようです。
と言うわけで
TextObjectの型を準備して、先程準備したHeaderBlockのTextの型を*TextObjectにしてしまいましょう。
type TextObject struct {
Type string `json:"type"`
Text string `json:"text"`
Emoji bool `json:"emoji,omitempty"`
Verbatim bool `json:"verbatim,omitempty"`
}
type HeaderBlock struct {
Type string `json:"type"`
Text *TextObject `json:"text"`
BlockID string `json:"block_id,omitempty"`
}
今回は特にBlockIDやVerbatimを使用する予定はないのですが、今後のことを考えて実装してしまいます。
以下同じようなことを繰り返すので、十分わかったよって人は飛ばしちゃってください。
Sectionのplain textブロックを準備する
「本日の癒し」の箇所です。シンプルそうですね。
こちら を参考に作ります
type SectionBlocks struct {
Type string `json:"type"`
Text *TextObject `json:"text"`
BlockID string `json:"block_id,omitempty"`
Fields string `json:"fields,omitempty"`
Accessory interface {} `json:"accessory,omitempty"`
}
…あまりシンプルじゃなかった
Imageのnotilteブロックを準備する
お待ちかねのふわたろうの画像の箇所です!
こちら を参考に作ります
type ImageBlock struct {
Type string `json:"type"`
ImageURL string `json:"image_url"`
AltText string `json:"alt_text"`
Title *TextObject `json:"title,omitempty"`
BlockID string `json:"block_id,omitempty"`
}
↓この箇所です。ボタンを押すとそれぞれのTwitter へ遷移します。
こちら を参考に作ります。
type ActionBlock struct {
Type string `json:"type"`
Elements []interface {} `json:"elements"`
BlockID string `json:"block_id,omitempty"`
}
またelementsとしてButton element を使用するため、こちらの構造体も準備します。
type ButtonElement struct {
Type string `json:"type"`
Text interface {} `json:"text"`
ActionId string `json:"action_id,omitempty"`
URL string `json:"url,omitempty"`
Value string `json:"value,omitempty"`
Style string `json:"style,omitempty"`
Confirm interface {} `json:"confirm,omitempty"`
}
Contextのtext and imagesブロックを準備する
一番下のブロックです。
こちら を参考に作ります。
type ContextBlock struct {
Type string `json:"type"`
Elements []interface {} `json:"elements"`
BlockID string `json:"block_id,omitempty"`
}
準備した構造体に値を突っ込む
長々と準備しました構造体に値をセットします。
func buildBlocks() []interface {} {
return []interface {}{
&HeaderBlock{
Type: "header" ,
Text: &TextObject{
Type: "plain_text" ,
Text: ":star2:癒しタイム:star2:" ,
},
},
&SectionBlocks{
Type: "section" ,
Text: &TextObject{
Type: "mrkdwn" ,
Text: "本日の癒し" ,
},
},
&ImageBlock{
Type: "image" ,
ImageURL: "https://imageURL" ,
AltText: "fuwataro" ,
},
&ActionBlock{
Type: "actions" ,
Elements: []interface {}{
&ButtonElement{
Type: "button" ,
Text: &TextObject{
Type: "plain_text" ,
Text: "ふわたろう" ,
Emoji: true ,
},
URL: "https://twitter.com/huwataro_" ,
Value: "fuwataro Twitter" ,
},
&ButtonElement{
Type: "button" ,
Text: &TextObject{
Type: "plain_text" ,
Text: "inoriko" ,
Emoji: true ,
},
URL: "https://twitter.com/inoriko711" ,
Value: "inoriko Twitter" ,
},
&ButtonElement{
Type: "button" ,
Text: &TextObject{
Type: "plain_text" ,
Text: "Fuller, Inc." ,
Emoji: true ,
},
URL: "https://twitter.com/fuller_inc" ,
Value: "fuller Twitter" ,
},
},
},
&ContextBlock{
Type: "context" ,
Elements: []interface {}{
&ImageBlock{
Type: "image" ,
ImageURL: "https://imageURL" ,
AltText: "inoriko711" ,
},
&TextObject{
Type: "plain_text" ,
Text: "Author: inoriko711" ,
Emoji: true ,
},
},
},
}
}
実行してみる
body JSON にblocks要素を付与。
bodyJSON, err := json.Marshal(map [string ]interface {}{
"username" : "inoriko711" ,
"icon_url" : "https://iconURL" ,
"text" : "癒し画像のお届け" ,
"blocks" : blocks,
})
go run 実行!!!!
投稿できました。