
JiraのラベルをREST APIで事前GETなしに追加・削除する
どうも!オペ部の西村祐二です!
JiraのラベルをAPIから付け外しするとき、fields.labelsへの指定は配列の丸ごと置換になります。そのため「GETで現在のラベルを取得 → 手元でマージ → PUTで書き戻す」という手順を踏みがちです。この方式ではリクエスト数が増えるうえ、GETとPUTの間に他の更新が入ると、その変更を上書きしてしまいます。実際、筆者の手元のアプリケーションでもこの方式で、課題1件あたりGET 2回 + PUT 3回を発行していました。
Edit issue APIのupdate操作を使うと、事前GETなしの1リクエストでラベルの追加・削除だけをサーバ側に反映できたので、検証結果と合わせて紹介します。
今回やること
この記事で分かること:
update.labelsのadd / removeで、事前GETなしにラベルを追加・削除する方法fieldsとupdateの違いと使い分け- 他フィールド(期日など)を同一リクエストで組み合わせる方法
fieldsとupdateの違い
Edit issue(PUT /rest/api/3/issue/{issueIdOrKey})のリクエストボディでは、フィールドの編集をfieldsとupdateの2通りで指定できます。
- fields: 値をそのまま設定する単純な方式。配列フィールドは送った配列で丸ごと置換される
- update:
set/add/remove/edit/copyという操作(verb)を指定する方式。配列フィールドへの要素の追加・削除を操作として表現できる
update.labelsなら「このラベルを足す」「このラベルを消す」という操作だけを送るので、現在値を知らなくても他のラベルに影響しません。値を丸ごと設定するならfields、配列の部分更新ならupdateという使い分けになります。
なお、公式リファレンスには同じフィールドをfieldsとupdateの両方に含められないことが明記されています("Fields included in here cannot be included in update.")。
試してみる
検証環境
- Jira Cloud(REST API v3)
- macOS + curl
- 認証: AtlassianアカウントのAPIトークンを使ったBasic認証。メールアドレスとAPIトークンを環境変数
JIRA_EMAIL/JIRA_API_TOKENにセットしておきます - 検証日: 2026-08-31
検証に使った課題には、あらかじめ4つのラベルが付いています。
curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
"https://your-domain.atlassian.net/rest/api/3/issue/ISSUE-1?fields=labels" | jq -c '.fields.labels'
["existing-a","existing-b","existing-c","existing-d"]
1. ラベルを追加する
update.labelsにaddを1つ入れてPUTします。
curl -s -o /dev/null -w "%{http_code}\n" \
-u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
-X PUT -H "Content-Type: application/json" \
"https://your-domain.atlassian.net/rest/api/3/issue/ISSUE-1" \
-d '{"update":{"labels":[{"add":"new-label"}]}}'
結果は204(No Content)でした。GETでラベルを確認すると、既存の4ラベルはそのままで、指定したラベルだけが追加されています。
["existing-a","existing-b","existing-c","existing-d","new-label"]
2. 追加と削除を1リクエストで行う
「古いラベルを外して新しいラベルを付ける」という付け替えも、addとremoveを並べれば1リクエストで済みます。
curl -s -o /dev/null -w "%{http_code}\n" \
-u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
-X PUT -H "Content-Type: application/json" \
"https://your-domain.atlassian.net/rest/api/3/issue/ISSUE-1" \
-d '{"update":{"labels":[{"add":"replacement-label"},{"remove":"new-label"}]}}'
結果は204で、GETで確認すると両方の操作が反映されていました。
["existing-a","existing-b","existing-c","existing-d","replacement-label"]
3. 別フィールドと同時に更新する
fieldsとupdateは、同じフィールドを指定しない限り1つのリクエストに同居できます。ラベルの追加と期日の設定を同時に行ってみます。
curl -s -o /dev/null -w "%{http_code}\n" \
-u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
-X PUT -H "Content-Type: application/json" \
"https://your-domain.atlassian.net/rest/api/3/issue/ISSUE-1" \
-d '{"update":{"labels":[{"add":"another-label"}]},"fields":{"duedate":"2026-09-30"}}'
結果は204で、GETで確認するとラベルの追加とduedateの設定が1回のPUTで反映されていました。
{"labels":["existing-a","existing-b","existing-c","existing-d","replacement-label","another-label"],"duedate":"2026-09-30"}
挙動のポイント
- 同じフィールドを両方に書くと400になる
- 公式リファレンスの記載どおり、
fields.labelsとupdate.labelsを同時に送ると、Field 'labels' cannot appear in both 'fields' and 'update'というエラーメッセージとともに400が返りました
- 公式リファレンスの記載どおり、
- 存在しないラベルのremoveはエラーにならない
- 付いていないラベルを
removeしても204が返り、他のラベルにも影響しませんでした。同じリクエストを繰り返しても結果が変わらないので、リトライしやすい挙動です
- 付いていないラベルを
- 更新後の状態は
returnIssue=trueで受け取れる- 成功時のレスポンスはデフォルトでは
204でボディが返りませんが、クエリパラメータreturnIssue=trueを付けると200で更新後の課題が返ることも確認しました。反映確認のためのGETも省けます
- 成功時のレスポンスはデフォルトでは
まとめ
GET → マージ → PUTのread-modify-writeをupdate.labelsのadd / removeに置き換えると、リクエスト数が減り、並行更新との競合も避けられます。冒頭で触れた手元のアプリケーションも、この置き換えで課題1件あたりPUT 1回に削減できました。
ラベル以外の配列フィールドにも同様の操作が定義されているので、部分更新をしたい場面ではまずupdateが使えないか確認するのが良さそうです。
誰かの参考になれば幸いです。
参考リンク:





