Ribbit's works

上限を気にせずPOST, PUT, DELETEする【kintone】

#kintone #JavaScript
にメンテナンス済み
記事のトップ画像

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

2021 年 8 月現在は、以下の通りです。

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

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

レコードの GET については、cybozu developer network に素敵なコードが掲載されていましたが、POST、PUT、DELETE については乗っていませんでした。 参考:全てのレコードの取得

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

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

ソースコード

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

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

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

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

const postAllRecords = async (app, _records) => {
  const records = [..._records];

  // レコードがなくなるまで、上限数ずつ実行
  while (records.length) {
    await kintone.api(kintone.api.url(`${END_POINT}records`, true), 'POST', {
      app: app,
      records: records.slice(0, LIMIT_POST),
    });
    records.splice(0, LIMIT_POST);
  }
};

bulkRequest を使用した場合

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

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

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

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

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

const bulkRequest = async (_requests) => {
  const requests = [..._requests];

  const responses = [];

  while (requests.length) {
    responses.push(
      await kintone.api(kintone.api.url(`${END_POINT}bulkRequest`, true), 'POST', {
        requests: requests.slice(0, LIMIT_BULK_REQUEST),
      })
    );
    requests.splice(0, LIMIT_BULK_REQUEST);
  }

  return responses;
};

const postAllRecords = async (app, _records) => {
  const records = [..._records];

  const payloads = [];

  while (records.length) {
    payloads.push({
      app,
      records: records.slice(0, LIMIT_POST),
    });
    records.splice(0, LIMIT_POST);
  }

  const requestBase = {
    method: 'POST',
    api: `${END_POINT}records.json`,
  };

  const requests = payloads.map((payload) => ({
    ...requestBase,
    payload,
  }));

  return bulkRequest(requests);
};

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

bulkRequest を使用していることを意識させないようにするには、返り値を均しておく必要があります。

return responses.map(({ results }) => results).flat();

PUT・DELETE の場合

サンプルでは POST のパターンを紹介しましたが、メソッドを変更するだけで PUT・DELETE にも対応可能です。

注意すべき点は、POST・PUT・DELETE でサンプルコードの引数に当たる_records の内容が変化するということです。

POST の場合は kintone レコードデータの配列でしたが、PUT の場合は以下のように、レコード番号と kintone レコードを格納したオブジェクトの配列となります。

また、DELETE の場合はレコード番号の配列となります。

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

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

注意すべきこと

もし処理の途中で失敗したとしても、データがロールバックしません。

例えば、データを 5,000 件一括で登録する処理を実行し、3,000 件目でエラーが出たとします。

bulkRequest を活用した方法では、

POST リクエストの上限レコード数 × bulkRequest の上限リクエスト数

である 2,000 件以内であれば、失敗してもロールバックしますが、2,000 件目以降でエラーが発生した場合、最初に実行した 2,000 件は削除されません。

これは現段階では API 上で解決することはできないため、よりセキュアな実行を目指すためには、あらかじめデータの整合性をチェックするしかありません。