こんにちは。ざわかける!のざわ(@zw_kakeru)です。
ConfluenceのAPIを使ってページ内にインラインコメントを投稿しようとして格闘した時の記録です。
起こったこと
pythonからConfluneceの記事を色々いじって遊んでいた時のことです。
ConfluenceのAPIを使って特定のページの特定の文言の部分にインラインコメントを表示させたくなりました。
公式ドキュメントによると、インラインコメントを投げるAPIとしてCreate inline commentが用意されているので、これを使えば良さそうです。
ページをこんな感じで用意して、

スクリプトを書いてみます。
(今回はpythonではなくシェルスクリプトです。)
curl --request POST \
--url 'https://mydomain/wiki/api/v2/inline-comments' \
--user 'myname@email.com:API_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"pageId": "11111111",
"body": {
"representation": "storage",
"value": "<p>あああ</p>"
},
"inlineCommentProperties": {
"textSelection": "何回",
"textSelectionMatchCount": 1,
"textSelectionMatchIndex": 0
}
}'
記事内の「何回」と書かれている部分にハイライトを当てて、「あああ」というインラインコメントを表示させてみましょう。
すると結果がこのようになりました。

400エラー。。は良いのですが、エラーメッセージにヒントが無さすぎて何をどう修正したら良いのか全然分からないですね。
detail: nullは非常に困ります。
というわけで、どうすれば正常終了できるのか色々試してみました。
やったこと
公式ドキュメントとにらめっこしながら色々ガチャガチャやってみて分かったことをまとめます。
textSelectionMatchCountとtextSelectionMatchIndexの指定
そのテキスト内に検索したい文字列が何個存在しているかを表すtextSelectionMatchCountと、さらにその中の何番目の文字列にインラインコメントをつけたいかを指定するtextSelectionMatchIndexですが、これらの値をきちんと正しいものに指定しないとエラーになります。
textSelectionMatchIndexの方はそりゃそうだろうという感じですが、textSelectionMatchCountの方も、間違った数値を入力していたらダメみたいです。
検索したい文字列がそのテキスト内に何個出てきているかなんて普通知らないので、スクリプトから実行するにはこの値を自前で求める必要があります。
エラーが返ってくるということはリクエストを投げた先でもチェックを行ってるはずですが、クライアント側でこの値を渡す必要ないんじゃ。。と思ってしまいます。
今回の記事では「何回」という単語が12回出てきていたのでtextSelectionMatchCountは12を指定し、その中の2番目の「何回」にインラインコメントをつけてみようと思ったのでtextSelectionMatchIndexに1を指定します。
(textSelectionMatchIndexは0始まりです。渡した値を使って配列が作られてる雰囲気を感じますね。)
...
"inlineCommentProperties": {
"textSelection": "何回",
"textSelectionMatchCount": 12,
"textSelectionMatchIndex": 1
}
...
これでtextSelectionMatchCountとtextSelectionMatchIndexは正常挙動をするようになりました。
文字コードについて
上記の対応をしても変わらず400エラーが出ていました。
理由が分からなかったのですが、もしかして日本語を指定してるからかな?と思い試しに「何回」ではなく「fight」という文字列にコメントをつけるようにしてリクエストを投げてみました。
するとコマンドが正常終了し、コンフルを確認すると確かにfightの文字列にインラインコメントが投稿されていました!

投稿は一旦できたものの、どうやら文字コードがバグっているみたいです。
だからサーバー側で文字列検索してもヒットせず、コメントがつけれなかったのですね。理解できました。
そういえば前回の記事でGet pageをした時、地のresponse.textはUnicodeで出力されていたな。。
ということを思い出し、じゃあ全部Unicodeで指定したらいけるんじゃないかと試してみました。
curl --request POST \
--url 'https://mydomain/wiki/api/v2/inline-comments' \
--user 'myname@email.com:API_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"pageId": "11111111",
"body": {
"representation": "storage",
"value": "<p>\u300c\u8ca0\u3051\u306a\u3044\u300d</p>"
},
"inlineCommentProperties": {
"textSelection": "\u30ad\u30bf\u30b5\u30f3\u30d6\u30e9\u30c3\u30af",
"textSelectionMatchCount": 2,
"textSelectionMatchIndex": 0
}
}'
何の文字列を指定してるのか分からないと思いますが、「負けない」という文字列に「キタサンブラック」というインラインコメントをつけようとしています。
こちらを実行してみたところ、結果がこのようになりました。

おおー。
無事にコメントをつけることができましたね。
やっとやりたかったことが実現できました。
サーバー側では全部Unicodeで管理してるのでしょうか、、
まあスクリプト側で変換処理を挟めばいい話ではあるのですがちょっと面倒ですね。。
おわりに
textSelectionMatchCountってこれいちいち指定する意味あるんでしょうかね。。
しかも正確な値を指定しないとエラーになるので、使う側からすると一手間かかってしまうなという気持ちになりました。
Unicodeの件も、なんかサーバー側でうまくやってくれよと思いますが、まあともあれちゃんと動かすことができたのでよしとしましょう。
こういうちょっとしたところでつまずく系の問題はメモを残しておく価値が結構あると思うので、こうしてサクッと書いておきました。
以上です。
おまけ
公式ドキュメントにtextSelectionMatchCountとtextSelectionMatchIndexの説明が書かれているのですが、

ここに、「textSelectionMatchCounは必ずtextSelectionMatchIndexよりも大きい値でないといけない」と書かれていて、実際そのように指定しないとエラーになるのですが、ここに載ってる例を見るとtextSelectionMatchIndexの方が大きくね。。。???
謎ですねえ。