bulkRequest

にメンテナンス済み

kintone REST API の bulkRequest は、複数の API リクエストを 1 回のリクエストにまとめて送信できる機能です。通常の REST API では操作ごとに個別のリクエストが必要ですが、bulkRequest を使えば最大 20 件のリクエストを一括で実行でき、しかもすべての操作がアトミック(全成功 or 全失敗)に処理されます。

この記事では、bulkRequest の基本的な使い方から、実践的な活用パターンまで解説します。

bulkRequest とは

通常の API との違い

項目通常の REST APIbulkRequest
リクエスト数操作ごとに 1 リクエスト最大 20 操作を 1 リクエスト
原子性なし(個別に成功/失敗)あり(全成功 or 全失敗)
エンドポイント各操作に対応する URL/k/v1/bulkRequest.json
対応操作-POST/PUT/DELETE 系のみ(GET 不可)
1 操作あたり上限100 件100 件(通常と同じ)
アトミックな処理

bulkRequest 内のいずれかのリクエストがエラーになった場合、すべてのリクエストがロールバックされます。データの整合性が重要な場面で特に有効です。

対応する API

bulkRequest で実行できる API は以下の通りです。

APIメソッドエンドポイント上限
レコード追加(1 件)POST/k/v1/record.json-
レコード追加(複数件)POST/k/v1/records.json100 件
レコード更新(1 件)PUT/k/v1/record.json-
レコード更新(複数件)PUT/k/v1/records.json100 件
レコード削除DELETE/k/v1/records.json100 件
ステータス変更PUT/k/v1/record/status.json-
ステータス一括変更PUT/k/v1/records/status.json100 件
チェック

GET 系の API(レコード取得、アプリ情報取得など)は bulkRequest で実行できません。bulkRequest は書き込み系の操作のみに対応しています。

基本的な使い方

kintone から利用する場合

bulk-request-basic.js
(() => {
  'use strict';

  /**
   * bulkRequest を実行する
   * @param { Object[] } requests - 実行するリクエストの配列
   * @returns { Promise<{ results: Object[] }> }
   */
  const executeBulkRequest = (requests) => {
    return kintone.api(kintone.api.url('/k/v1/bulkRequest.json', true), 'POST', {
      requests,
    });
  };

  // 使用例: レコードの追加と更新を同時に実行
  const events = ['app.record.detail.show'];

  kintone.events.on(events, async (event) => {
    const appId = kintone.app.getId();

    const requests = [
      {
        method: 'POST',
        api: '/k/v1/records.json',
        payload: {
          app: appId,
          records: [
            { '案件名': { value: '新規案件A' }, 'ステータス': { value: '未着手' } },
            { '案件名': { value: '新規案件B' }, 'ステータス': { value: '未着手' } },
          ],
        },
      },
      {
        method: 'PUT',
        api: '/k/v1/records.json',
        payload: {
          app: appId,
          records: [
            { id: 1, record: { 'ステータス': { value: '完了' } } },
            { id: 2, record: { 'ステータス': { value: '完了' } } },
          ],
        },
      },
    ];

    try {
      const { results } = await executeBulkRequest(requests);
      console.log('bulkRequest 成功:', results);
    } catch (error) {
      console.error('bulkRequest エラー:', error);
    }

    return event;
  });
})();
チェック

bulkRequest 内の api プロパティにはゲストスペース用のパスも指定できます。ゲストスペース内のアプリの場合は /k/guest/ {スペースID}/v1/records.json のように指定してください。

Node.js から利用する場合

bulk-request-nodejs.js
const fetch = require('node-fetch');

const DOMAIN = 'your-subdomain.cybozu.com';
const TOKEN = 'your-api-token';

/**
 * bulkRequest を実行する
 * @param { Object[] } requests - 実行するリクエストの配列
 * @returns { Promise<{ results: Object[] }> }
 */
const executeBulkRequest = async (requests) => {
  const response = await fetch(`https://${DOMAIN}/k/v1/bulkRequest.json`, {
    method: 'POST',
    headers: {
      'X-Cybozu-API-Token': TOKEN,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ requests }),
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(JSON.stringify(error));
  }

  return response.json();
};
Node.js環境でのREST API Client
REST API Client を活用するうえで、私が注意しているポイントを紹介します。

実践パターン

パターン 1: アプリ間のデータ同期

あるアプリのレコードを別のアプリにコピーし、元のアプリのステータスを更新する処理です。bulkRequest を使うことで、コピー失敗時にステータスだけ更新される不整合を防ぎます。

bulk-sync-apps.js
(() => {
  'use strict';

  /**
   * レコードを別アプリにコピーし、元アプリのステータスを更新する
   * @param { Object } params
   * @param { number } params.sourceAppId - コピー元アプリID
   * @param { number } params.targetAppId - コピー先アプリID
   * @param { Object[] } params.records - コピーするレコード
   */
  const syncRecords = async (params) => {
    const { sourceAppId, targetAppId, records } = params;

    // コピー先に追加するレコード
    const newRecords = records.map((record) => ({
      '案件名': { value: record['案件名'].value },
      '金額': { value: record['金額'].value },
      '元アプリレコードID': { value: record['$id'].value },
    }));

    // 元アプリのステータスを更新
    const updateRecords = records.map((record) => ({
      id: record['$id'].value,
      record: {
        'コピー済み': { value: ['済'] },
      },
    }));

    const requests = [
      {
        method: 'POST',
        api: '/k/v1/records.json',
        payload: { app: targetAppId, records: newRecords },
      },
      {
        method: 'PUT',
        api: '/k/v1/records.json',
        payload: { app: sourceAppId, records: updateRecords },
      },
    ];

    return kintone.api(kintone.api.url('/k/v1/bulkRequest.json', true), 'POST', {
      requests,
    });
  };
})();

パターン 2: 安全なデリートインサート

古いデータを削除してから新しいデータを登録する処理を、bulkRequest でアトミックに実行します。

bulk-delete-insert.js
(() => {
  'use strict';

  /**
   * 指定条件のレコードを削除してから新しいレコードを登録する
   * @param { Object } params
   * @param { number } params.app - アプリID
   * @param { number[] } params.deleteIds - 削除するレコードIDの配列
   * @param { Object[] } params.newRecords - 登録する新しいレコードの配列
   */
  const deleteAndInsert = async (params) => {
    const { app, deleteIds, newRecords } = params;

    const requests = [];

    // 削除リクエスト(100 件ずつ分割)
    for (let i = 0; i < deleteIds.length; i += 100) {
      const chunk = deleteIds.slice(i, i + 100);
      requests.push({
        method: 'DELETE',
        api: '/k/v1/records.json',
        payload: { app, ids: chunk },
      });
    }

    // 追加リクエスト(100 件ずつ分割)
    for (let i = 0; i < newRecords.length; i += 100) {
      const chunk = newRecords.slice(i, i + 100);
      requests.push({
        method: 'POST',
        api: '/k/v1/records.json',
        payload: { app, records: chunk },
      });
    }

    // bulkRequest は最大 20 リクエスト
    if (requests.length > 20) {
      throw new Error(
        `bulkRequest の上限(20)を超えています: ${requests.length} リクエスト`
      );
    }

    return kintone.api(kintone.api.url('/k/v1/bulkRequest.json', true), 'POST', {
      requests,
    });
  };
})();
レコードのデリートインサート
APIを使ってレコードを更新したい場合、基本的にはPUT APIを使用します。ただ、仕様や安全性を考慮し、一定条件のレコードを全て削除したうえで、レコードを再生成しなければならない状況も起こりえます。今回はそういった場合のコードサンプルを紹

パターン 3: ステータスの一括変更

複数レコードのプロセス管理ステータスを一括で変更する処理です。

bulk-status-update.js
(() => {
  'use strict';

  /**
   * 複数レコードのステータスを一括変更する
   * @param { Object } params
   * @param { number } params.app - アプリID
   * @param { Object[] } params.statusUpdates - ステータス変更情報の配列
   */
  const bulkUpdateStatus = async (params) => {
    const { app, statusUpdates } = params;

    // 100 件ずつ分割
    const requests = [];
    for (let i = 0; i < statusUpdates.length; i += 100) {
      const chunk = statusUpdates.slice(i, i + 100);
      requests.push({
        method: 'PUT',
        api: '/k/v1/records/status.json',
        payload: {
          app,
          records: chunk.map((item) => ({
            id: item.id,
            action: item.action,
            assignee: item.assignee,
          })),
        },
      });
    }

    return kintone.api(kintone.api.url('/k/v1/bulkRequest.json', true), 'POST', {
      requests,
    });
  };

  // 使用例
  // bulkUpdateStatus({
  //   app: 123,
  //   statusUpdates: [
  //     { id: 1, action: '承認する', assignee: 'user1' },
  //     { id: 2, action: '承認する', assignee: 'user1' },
  //   ],
  // });
})();
プロセス管理のカスタマイズ
kintone のプロセス管理機能をJavaScriptカスタマイズで拡張する方法を解説します。ステータス変更イベントの活用、ステータスに応じたフィールド制御、プロセス管理 REST API によるステータス操作まで紹介します。

エラーハンドリング

bulkRequest でエラーが発生した場合、レスポンスにはどのリクエストでエラーが発生したかの情報が含まれます。

bulk-error-handling.js
try {
  const { results } = await kintone.api(
    kintone.api.url('/k/v1/bulkRequest.json', true),
    'POST',
    { requests }
  );
  console.log('成功:', results);
} catch (error) {
  // error.message にはエラーの詳細が含まれる
  console.error('bulkRequest エラー:', error.message);

  // エラーレスポンスの例:
  // {
  //   "results": [
  //     {},  // 1 番目のリクエストは問題なし
  //     {    // 2 番目のリクエストでエラー
  //       "message": "不正なフィールドが...",
  //       "id": "xxxxx",
  //       "code": "CB_VA01"
  //     }
  //   ]
  // }
}
よくあるエラーコード

CB_VA01 は必須フィールドの未入力、CB_NO02 は権限不足、GAIA_RE18 はリクエスト数の上限超過を示します。エラーコードに応じた適切なメッセージをユーザーに表示してください。

制限事項

bulkRequest を使用する際の制限事項を整理します。

制限項目上限値
1 回の bulkRequest のリクエスト数最大 20 件
各リクエスト内のレコード数最大 100 件(通常の API と同じ)
GET 系 API の使用不可
アプリの横断可能(異なるアプリの操作を混在可)
ゲストスペースapi パスにスペース ID を含めれば可
API トークン全リクエストで使用するアプリの権限が必要
API トークンの権限

bulkRequest で複数のアプリを操作する場合、すべてのアプリに対するアクセス権を持つ API トークンが必要です。異なるアプリの API トークンをカンマ区切りで指定することも可能です(例: X-Cybozu-API-Token: token1, token2)。

POST, PUT, DELETEの上限
kintone REST APIには、GET, POST, PUT, DELETEそれぞれに、1度に操作できるレコードの上限が設けられています。今回は上記のレコード上限を気にすることなく、一括でレコードの作成ができる関数をご紹介します。RE

まとめ

  • bulkRequest は最大 20 件の書き込み系 API リクエストを 1 回のリクエストで一括実行できる
  • すべての操作がアトミックに処理されるため、一部だけ成功する不整合を防げる
  • アプリ間のデータ同期、デリートインサート、ステータスの一括変更などに有効
  • GET 系の API は bulkRequest では使用できない
  • 各リクエスト内のレコード数は通常と同じく最大 100 件
  • 複数アプリを操作する場合は、全アプリのアクセス権を持つ API トークンが必要

練習問題

bulkRequest で 1 回のリクエストに含められる API 操作の最大件数はいくつですか?

bulkRequest の特徴として正しいものはどれですか?

bulkRequest で複数のアプリのレコードを操作する場合、API トークンの扱いとして正しいものはどれですか?

#kintone #JavaScript #TypeScript