目指せ!JavaScript カスタマイズ中級者(4)〜kintone REST API Client 編〜

目次

はじめに

目指せ!JavaScriptカスタマイズ中級者(1)〜webpack 編〜では複数のアプリカスタマイズを扱うためのwebpackの導入をしていました。
今回は同じwebpackの環境で、kintone REST APIを扱うのに便利なkintone REST API Clientをインストールして利用できるようにし、簡単に使い方をお伝えします。

目指せ中級者シリーズの記事一覧は以下を参照してください。
目指せ中級者シリーズ

kintone REST API Client とは

kintone REST API Clientは、kintone REST APIを利用するためのライブラリです。
たとえば次のようなレコードやアプリの操作が簡単にできます。

  • レコード全件取得
  • アップサート(既存のデータがあったらアップデートし、なかったらインサートする)

もともと、同じ用途のライブラリーとして kintone JS SDK (External link) というものもありますが、そちらは利用非推奨となっています。
今までkintone JS SDKを使っていた方も今回紹介するkintone REST API Clientをぜひ利用いただければと思います。

使うための準備

目指せ!JavaScriptカスタマイズ中級者(1) 〜webpack編〜で説明したようにJavaScriptファイルをbuildできるようになっているのが前提です。

下記をコマンドラインから入力し実行します。

1
npm install @kintone/rest-api-client

これでインストールが始まり、kintone REST API Clientを利用できます。
初めて利用する方は以下の記事のQuickStartをやってみるとよいでしょう。
kintone JavaScript Client (@kintone/rest-api-client)

使い方

GitHubのkintone-rest-api-client (External link) のページに利用方法などが書かれていますが、英語ですのでリファレンスのどこを参照すればよいかを説明します。

リファレンス

Record (External link)

レコードの取得や作成などレコードの操作に関することが記載されています。
通常、このリファレンスが基本になると思います。

App (External link)

アプリの設定変更の操作に関することが記載されています。
アプリの設定を自動で変更したいなどがあれば使いますが、見る頻度は基本的に低いはずです。

File (External link)

ファイルのアップロード、ダウンロードに関することが記載されています。
レコードにファイルを添付したい場合などもこちらを利用することになります。

BulkRequest (External link)

複数アプリへのレコード一括処理に関することが記載されています。

リファレンスの読み方

リファレンスの各項目には、その関数の説明と、Parameters(関数の引数)とReturns(関数の戻り値)があります。
英語で読み取れないところはGoogle翻訳などを利用すれば理解の一助になるかと思います。

  1. 関数名
  2. 関数の説明
  3. 関数の戻り値
  4. 関数の引数

使用例

リファレンスに記載されているものから一部、使用例を次に示します。
async/await形式で記述します。
参考にしてください。

レコードを取得

アプリIDが「1」でレコード番号が「10」のレコードを取得したい場合の例です。

1
const res = await client.record.getRecord({app: '1', id: '10'});

レコードを一括取得

2020年7月定期メンテナンスで、それ以降に作られるアプリはoffset上限が1万件となってしまったため、レコードを全件取得する場合は カーソル APIを使う必要があります。

ですが、kintone REST API ClientではカーソルAPIを意識せずとも次のように全件取得できます。

アプリIDが「1」でフィールドコードが「price」、「priceが1000以上のもの」を取得したい場合の例です。

1
const res = await client.record.getAllRecords({app: '1', condition: 'price >= 1000'});

レコードの作成

アプリIDが「1」でフィールドコードが「fiel-cod-1」のフィールドに「サンプルテキスト」と入力されたレコードを作成したい場合の例です。

1
const res = await client.record.addRecord({app: '1', record: {field_code_1: {value: 'サンプルテキスト1'}}});

レコードの更新

アプリIDが「1」でレコードIDが「10」、フィールドコードが「fiel-cod-1」のフィールドに「サンプルテキスト2」と入力された状態にレコードを更新したい場合の例です。

1
const res = await client.record.updateRecord({app: '1', id: '10', record: {field_code_1: {value: 'サンプルテキスト2'}}});

レコードの複数更新

次のように、アプリIDが「1」のアプリに対し、次のレコードを一括で更新したい場合の例です。

  • レコードIDが「11」、フィールドコードが「fiel-cod-1」のフィールドに「サンプルテキスト1」と入力
  • レコードIDが「12」、フィールドコードが「fiel-cod-2」のフィールドに「サンプルテキスト2」と入力
  • レコードIDが「13」、フィールドコードが「fiel-cod-3」のフィールドに「サンプルテキスト3」と入力
1
2
3
4
5
6
7
8
9
const res = await client.record.updateAllRecords({
  app: 1,
  // レコードは、オブジェクトの配列で指定します。
  records: [
    {id: '11', record: {field_code_1: {value: 'サンプルテキスト1'}}},
    {id: '12', record: {field_code_2: {value: 'サンプルテキスト2'}}},
    {id: '13', record: {field_code_3: {value: 'サンプルテキスト3'}}},
  ]
});

レコードのアップサート

アップサートとは、該当するレコードがなければインサート(挿入・新規作成)、該当するレコードがあればアップデート(更新)をするための機能です。

次の内容でアップサートする例です。

  • アプリIDが「1」
  • 更新対象のレコード:更新のキーに利用するフィールドのフィールドコードが「fiel-key」で値が「apple」のレコード
  • 更新内容:フィールドコードが「fiel-cod-1」のフィールドに「サンプルテキスト1」と入力
1
2
3
const res = await client.record.upsertRecord({
  app: '1', updateKey: {field: 'field_key', value: 'apple'}, record: {field_code_1: {value: 'サンプルテキスト1'}}
});

サンプル

アプリ間のデータのやりとりでkintone REST API Clientを中心に使ったサンプルを示します。

シナリオ

kintoneアプリストアに、見積書アプリと商品リストアプリの2つのアプリがパックになっている「商品見積書パック」というものがあります。
見積書アプリで見積作成時に、ルックアップフィールドを用いて商品リストアプリにある商品を選べるものです。

それを利用して、次の仕様を満たすようアプリのカスタマイズとJavaScriptカスタマイズを行います。

  1. 見積作成時(見積アプリでレコード保存時)に、選択されている商品の在庫数を減らす。
  2. 見積作成時(見積アプリでレコード保存時)に、選択されている商品の在庫がない場合はエラーを表示する。

保存時のイメージ

レコードを保存したときの動作イメージは次のとおりです。

  • 保存時に、数量分の、在庫数がなければ保存させない。
  • 在庫がある場合は、在庫引当処理を行う(商品リストアプリの在庫数をへらす)

なお「在庫数」フィールドは今回のサンプルで追加します。

アプリの用意と設定

アプリの用意

kintoneアプリストアにある 商品見積書パック (External link) を選び「このアプリパックを追加」を押して追加してください。

アプリの設定

商品リストアプリに、フィールド名とフィールドコードが「在庫数」のフィールドを追加してください。
また、見積書アプリからルックアップするためのレコードを1つ以上登録してください。

JavaScript カスタマイズ

コードを書き、ビルドしたものを見積書アプリにアップロードしてください。

コードは、以下のリポジトリにも公開しています。
https://github.com/cybozudevnet/sample-kintone-webpack-for-intermediate/tree/master/src/apps/quote (External link)

ビルドやアップロード方法については 目指せ!JavaScript カスタマイズ中級者(2)〜自動で一括ファイルアップロード編〜などの記事を参照ください。

4行目のアプリIDについては、環境に合わせて書き換えてください。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import {KintoneRestAPIClient} from '@kintone/rest-api-client';

// 商品リストのアプリIDを入力してください
const productsAppId = 122;

const events = ['app.record.create.submit', 'app.record.edit.submit'];

kintone.events.on(events, async (event) => {
  const {record} = event;

  // kintoneへ接続するためのインスタンスを作成
  const client = new KintoneRestAPIClient();

  // 今回はコード簡略化のために、テーブルの商品は重複禁止とします。
  // ただの簡易的な重複チェックなので意味は理解しなくてOKです。
  const hasDuplicatedRow = record.見積明細.value.some((rowA, indexA, arr) => {
    return arr.find((rowB, indexB) => indexA !== indexB && rowA.value.型番.value === rowB.value.型番.value);
  });
  if (hasDuplicatedRow) {
    event.error = '重複した商品は登録できません。';
    return event;
  }

  // テーブルに入っている商品レコードを取得
  let products;
  try {
    products = await client.record.getRecords({
      app: productsAppId,
      query: `型番 in (${record.見積明細.value
        .map((row) => `"${row.value.型番.value}"`)
        .join(', ')})`,
    });
  } catch (error) {
    event.error = 'レコードの取得に失敗しました';
    return event;
  }

  // 商品リストの在庫数を差し引いたデータを作成
  const deductedProductRecords = products.records.map((productRecord) => {
    const tableRow = record.見積明細.value.find(
      (row) => productRecord.型番.value === row.value.型番.value
    );

    // アップデートのキーとなる型番と, 差し引いた在庫数を格納する。
    return {
      型番: {
        value: productRecord.型番.value,
      },
      在庫数: {
        value: Number(productRecord.在庫数.value) - Number(tableRow.value.数量.value),
      },
    };
  });

  // 在庫数を差し引いたあと在庫数が0未満になるようなレコードがないか確認
  const noStockRecords = deductedProductRecords.filter(
    (productRecord) => Number(productRecord.在庫数.value) < 0
  );

  // 差し引き1未満のレコードがでた場合はエラーとみなしレコードの作成をストップさせる
  if (noStockRecords.length > 0) {
    // event.errorにデータをいれたあとeventを返すとレコードの作成をストップできる
    // どの商品が問題か示すために在庫が足りない商品の型番を列挙する
    event.error = `在庫がない商品があります。型番 ${noStockRecords
      .map((productRecord) => productRecord.型番.value)
      .join(', ')}`;

    return event;
  }

  // 問題なければアップデート
  try {
    await client.record.updateRecords({
      app: productsAppId,
      records: deductedProductRecords.map((productRecord) => {
        return {
          updateKey: {
            field: '型番',
            value: productRecord.型番.value,
          },
          record: {
            在庫数: {
              value: productRecord.在庫数.value,
            },
          },
        };
      }),
    });
  } catch (error) {
    event.error = `アップデートに失敗しました。${error.message}`;
    return event;
  }

  return event;
});

アップロードしたら、シナリオが実現できるか動作確認してください。

おわりに

kintoneのJavaScript APIをそのまま使い続けてももちろん問題ないですが、kintone REST API Clientを使うとより簡単にRESTでデータを扱えるようになるので、ぜひ利用してみてください。

information

このTipsは、2020年10月版kintoneと @kintone/rest-api-client@1.7.0で動作を確認しています。