【Slack CLI】block_idが衝突してSlackにメッセージを送れない
この記事は KINTOテクノロジーズアドベントカレンダー2024 の5日目の記事です🎅🎄
KINTOテクノロジーズで my route(iOS) を開発しているRyomm a.k.a 幻のbot職人 です。
まなびぃから小ネタです。
ここではSlack CLIの話として書いていますが、内部的にはSlack CLIもSlack APIを使用していますので、Slack APIを直接使用しているケースでも当てはまるかもしれません。
背景
Slack CLIで以下のような処理を行おうとしたとき、なぜかBlock Kitのメッセージが送れないことがありました。
- フォームの入力でrich_text型として値を受け取る
- 値をrich_text型としてDataStoreに保存
- DataStoreから保存したいくつかのrich_text型のデータを取り出して結合し、整形する
postMessage
を使って作成したblockを送信する
しかし、parameter_validation_failed
というエラーで落ちてしまいました。
原因
送信部分でパラメータ不正のエラーが出ており、送信しようとしていたblockを調べてみると、以下のように block_id
が重複していることがわかりました。
[
{
"type": "rich_text",
"block_id": "xdrwH", // <- this
"elements": [
/* ... */
]
}, {
"type": "rich_text",
"block_id": "xdrwH", // <- this
"elements": [
/* ... */
]
}
]
送ろうとしているメッセージの block_id
が衝突しているため、Slackにメッセージを送れないようです。
block_id
block_id
とは、ブロックの一意の識別子です。
公式ドキュメントには以下のように説明されています。
A unique identifier for a block. If not specified, a block_id will be generated. You can use this block_id when you receive an interaction payload to identify the source of the action. Maximum length for this field is 255 characters. block_id should be unique for each message and each iteration of a message. If a message is updated, use a new block_id.
block_id
を指定せずにブロックを作成した場合は、自動的に block_id
が生成されます。
主にインタラクティブなやり取りをしたい場合に使用します。例えばボタンが押された際にどのブロックのボタンを押されたのか?などの特定に役立ちます。
1回のメッセージ、もしくはメッセージの反復(=一連の双方向なやり取り)の中で一意である必要があります。
また、メッセージが更新された際には新しい block_id
を使用します。
今回のようにフォームでの入力の場合、受け取ったrich_textに含まれる block_id
は自動生成されたものになります。
さらに、冒頭の処理では入力で受け取るrich_textは別々のメッセージとして受け取っているため、 block_id
も重複している可能性があります。
実際に今回の問題は block_id
が衝突していることで起こりました。
ここで一句
なぜなのか 自動生成 信じてた 衝突するよ block_id
自動生成されたblock_idはUUID的な簡単には衝突しないものだと信じていたのに、衝突したなぁ...という唖然とした気持ちが表れていますね。
これは私の推測ですが、Slack側が自動生成する block_id
はブロックの内容をもとに作られていると思われます。
試しに全く同じ入力を行うと、全く同じ block_id
が取得できます。
rich_textにhogeと入力する
→ 毎回 RlmLN
というblock_idが生成される
{
"type": "rich_text",
"block_id": "RlmLN",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"text": "hoge",
"type": "text"
}
]
}
]
}
このため、全く同じ入力がある可能性がある場合、同じくらい block_id
が衝突する可能性もあると考えると良いでしょう。
解決策
さて、いくつかのブロックを結合して1つのメッセージとしてSlackに送りたいとき、メッセージ内のそれぞれのblock_idは一意にする必要があります。
インタラクティブな動作を行わない場合、 block_id
を保持する必要性はあまりないので削除してしまうのが一番シンプルな解決策です。
block_id
が指定されていない場合はSlack側が自動で生成してくれるため、 block_id
を削除したまま送信します。
これは整形を行なっているメソッドの一部です。delete演算子でオブジェクトからblock_idプロパティを削除しています。
// client.apps.datastore.query で取得した結果のitemsが引数eventに入る
// 参考: https://api.slack.com/methods/apps.datastore.query#examples
function eventMessage(event) {
// ...
event.description.forEach((description) => {
if (description.block_id) {
delete description.block_id // 🐈❗️
}
message.push(description)
})
// ...
}
これで block_id
の衝突を気にせずメッセージを送ることができるようになりました!
ただし、インタラクティブなやり取りをしたいときには、オブジェクトから block_id
を削除するのは良い方法ではないです。
その場合は、送信時にアプリ側で block_id
を作成して割り当てると良いと思います。
おわりに
block_id
が衝突してメッセージが送れないはなしでした!
関連記事 | Related Posts
We are hiring!
【iOSエンジニア】モバイルアプリ開発G/東京
モバイルアプリ開発GについてKINTOテクノロジーズにおける、モバイルアプリ開発のスペシャリストが集まっているグループです。KINTOやmy routeなどのサービスを開発・運用しているグループと協調しながら品質の高いモバイルアプリを開発し、サービスの発展に貢献する事を目標としています。
【iOSエンジニア】モバイルアプリ開発G/大阪
モバイルアプリ開発GについてKINTOテクノロジーズにおける、モバイルアプリ開発のスペシャリストが集まっているグループです。KINTOやmy routeなどのサービスを開発・運用しているグループと協調しながら品質の高いモバイルアプリを開発し、サービスの発展に貢献する事を目標としています。