POST, PUT, DELETEの上限

にメンテナンス済み

kintone REST API には、GET, POST, PUT, DELETE それぞれに、1 度に操作できるレコードの上限が設けられています。

レコード操作 API の 1 回あたりの上限は、以下の通りです(最新の仕様は cybozu developer network で確認してください)。

GET500 レコード/回
POST100 レコード/回
PUT100 レコード/回
DELETE100 レコード/回
一括処理(bulkRequest)20 リクエスト/回

下のシミュレータで 操作 と 戦略 を切り替えると、それぞれの上限に到達するまで何回 HTTP コールが必要になるかを視覚的に確認できます。bulkRequest を選ぶとコール数が大幅に削減されることが分かります。

kintone REST API 一括処理シミュレータ

chunk

レコード件数と戦略を選ぶと、API コールの並び・所要時間・上限超過を可視化します。

操作
戦略
速度
処理レコード
0 / 1,500
進捗 0%
HTTP コール
0 / 15
1コールあたり平均 100 件
シミュレート所要時間
0 ms
合計 4.5 s
ステータス
待機中
  1. 1
    POST/k/v1/records.json100 件·300 ms
    100 件を POST
  2. 2
    POST/k/v1/records.json100 件·300 ms
    100 件を POST
  3. 3
    POST/k/v1/records.json100 件·300 ms
    100 件を POST
  4. 4
    POST/k/v1/records.json100 件·300 ms
    100 件を POST
  5. 5
    POST/k/v1/records.json100 件·300 ms
    100 件を POST
  6. 6
    POST/k/v1/records.json100 件·300 ms
    100 件を POST
  7. 7
    POST/k/v1/records.json100 件·300 ms
    100 件を POST
  8. 8
    POST/k/v1/records.json100 件·300 ms
    100 件を POST
  9. 9
    POST/k/v1/records.json100 件·300 ms
    100 件を POST
  10. 10
    POST/k/v1/records.json100 件·300 ms
    100 件を POST
  11. 11
    POST/k/v1/records.json100 件·300 ms
    100 件を POST
  12. 12
    POST/k/v1/records.json100 件·300 ms
    100 件を POST
  13. 13
    POST/k/v1/records.json100 件·300 ms
    100 件を POST
  14. 14
    POST/k/v1/records.json100 件·300 ms
    100 件を POST
  15. 15
    POST/k/v1/records.json100 件·300 ms
    100 件を POST

REST API を使用するたびに kintone.api…と入力したり、エラー処理を作るのは手がかかるため、汎用的な関数やクラスを定義している方も少なくないと思いますが、そういった時に起きてしまいがちなのが、この上限に到達してしまう問題です。

レコードの GET については、cybozu developer network にカーソル API を使った全件取得のコードが掲載されていますが、POST、PUT、DELETE については掲載されていません。

参考:全てのレコードの取得

今回は上記のレコード上限を気にすることなく、一括でレコードの作成ができる関数をご紹介します。

今回紹介するのは POST のパターンだけですが、API のメソッドを変更することで、PUT・DELETE にも対応可能です。

ソースコード

1 つのリクエストを繰り返し、簡単に記述する

こちらが基本のコードです。実行したいレコード数が上限を上回っている場合、先頭から上限分ずつ API を実行し、最後に端数を実行する仕組みです。

/** REST APIのエンドポイント */
const END_POINT = '/k/v1/';

/** POSTで1度に扱えるレコード上限 */
const LIMIT_POST = 100;

/** 配列を指定したサイズで分割する */
const chunk = (arr, size) =>
  Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>
    arr.slice(i * size, i * size + size)
  );

const postAllRecords = async (app, records) => {
  const chunked = chunk(records, LIMIT_POST);

  for (const records of chunked) {
    await kintone.api(kintone.api.url(`${END_POINT}records`, true), 'POST', {
      app: app,
      records: records,
    });
  }
};

bulkRequest を使用した場合

前述した POST API のみ使用したパターンでは、エラーが発生した場合に 100 件単位でしかロールバックできません。

ロールバックできる件数を最大化したい場合は、以下の bulkRequest を活用したコードを使用します。

/** REST APIのエンドポイント */
const END_POINT = '/k/v1/';

/** POSTで1度に扱えるレコード上限 */
const LIMIT_POST = 100;

/** 同時に処理できるリクエスト上限 */
const LIMIT_BULK_REQUEST = 20;

/** 配列を指定したサイズで分割する */
const chunk = (arr, size) =>
  Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>
    arr.slice(i * size, i * size + size)
  );

const bulkRequest = async (requests) => {
  const responses = [];
  const chunkedRequests = chunk(requests, LIMIT_BULK_REQUEST);

  for (const requests of chunkedRequests) {
    responses.push(
      await kintone.api(kintone.api.url(`${END_POINT}bulkRequest`, true), 'POST', { requests })
    );
  }

  return responses;
};

const postAllRecords = async (app, records) => {
  const payloads = chunk(records, LIMIT_POST).map((records) => ({ app, records }));

  const requests = payloads.map((payload) => ({
    method: 'POST',
    api: `${END_POINT}records.json`,
    payload,
  }));

  return bulkRequest(requests);
};

bulkRequest の実行結果はオブジェクト型で、results の中に通常の API の実行結果が配列で格納されています。

bulkRequest を使用していることを意識させないようにするには、返り値を均しておく必要があります。例えば、次のように各レスポンスの results を 1 つの配列にまとめます。

// bulkRequest 関数の最後(return responses; の代わり)
return responses.flatMap(({ results }) => results);

PUT・DELETE の場合

サンプルでは POST のパターンを紹介しましたが、method を変更し、payload の形式を合わせれば PUT・DELETE にも対応可能です。

注意すべき点は、POST・PUT・DELETE でサンプルコードの引数 records に渡す内容と、リクエストの payload の形式が変化するということです。

POST の場合は kintone レコードデータの配列でしたが、PUT の場合は以下のように、レコード ID と kintone レコードを格納したオブジェクトの配列となります(payload は { app, records })。

また、DELETE の場合はレコード ID の配列となり、payload は { app, ids } の形式です。

// PUT
records = [
  { id: 1, record: kintoneRecord1 },
  { id: 2, record: kintoneRecord2 },
  //...
];

// DELETE
records = [
  1,
  2,
  3,
  4,
  5, //...
];

注意すべきこと

1 回の API 呼び出しの範囲を超えると、処理の途中で失敗しても、成功済みの分は自動でロールバックされません。

bulkRequest は、1 回の呼び出し内の処理がすべて成功するか、すべて取り消されるかのどちらかになります(トランザクション)。1 回で扱えるのは、

POST リクエストの上限レコード数 × bulkRequest の上限リクエスト数 = 100 × 20 = 2,000 件

までです。

例えば 5,000 件を登録する場合、bulkRequest は 2,000 件・2,000 件・1,000 件の 3 回に分かれます。3,000 件目でエラーが出たとすると、2 回目の bulkRequest(2,001〜4,000 件目)は取り消されますが、成功済みの 1 回目(1〜2,000 件目)は登録されたままです。

これは現段階では API 上で解決できないため、より安全に実行するには、あらかじめ入力データの整合性をチェックしておくことが重要です。失敗した場合に備えて、どこまで登録できたかをログに残しておくと再実行しやすくなります。

#kintone #JavaScript