Power Automate for desktop から kintone REST API を使用してレコード取得とレコード登録を行う


# はじめに
本記事は Power Automate for desktop から、kintone REST API を使用し、操作する方法についてまとめるものとなります。
Power Automate for desktop では、Web ブラウザーの操作が可能のため kintone をブラウザー越しに操作することが可能ですが、REST API を介した操作を実現することによってより安定的な自動化を行うことができる可能性があります。

GUI を用いた自動化と API を用いた自動化について、以下の発表でも私見をまとめていますのでよろしければご覧ください。

https://speakerdeck.com/maekawa123/power-automate-to-power-automate-for-desktop-noshi-ifen-kewokao-eru?slide=27

本記事は、Microsoft Power Automate Advent Calendar 2022 5 日目の記事です。

https://qiita.com/advent-calendar/2022/powerautomate


# 前提事項や免責事項
Power Automate for desktop Ver 2.26 で動作を確認しています。
kintone API トークンについて、この記事ではアクションに直書きしていますが、適切に保存して利用する必要があります。
(Azure Key Vault への格納などが対策になると思います)

セキュアコーディング ガイドライン

https://developer.cybozu.io/hc/ja/articles/201919400

# 事前準備
操作を行うアプリの API トークンを取得します。
取得方法は、kintone のヘルプページを詳細で分かりやすいです。

https://jp.cybozu.help/k/ja/user/app_settings/api_token.html


# 各種操作
kintone REST API の実行方法と実行結果の取得について記載します。

基本的には、API 仕様通りに API の実行および結果が取得できることを確認していますが、取得した結果へのデータアクセスなど PAD 側の動作に依存する点について解説します。

### 1. レコードの取得（GET）
アプリ上の特定の 1 レコードの情報を取得します。
kintone API を実行するために "Web サービスを呼び出します" アクション必要な設定を入力します。

このアクションで、重要なポイントは以下です。。
・カスタム ヘッダーに X-Cybozu-API-Token を設定し、API トークンを設定します。
・取得対象のアプリおよびレコードの ID は、HTTP のクエリ文字列として送信します。
※本アクションにおける GET メソッドで "本文" 項目の内容がリクエストに含まれないことを実行時のネットワーク トレースから確認しているので、クエリ文字列に設定する必要がありました。

上記を踏まえた各パラメータの設定は以下の通りです。

| プロパティ| パラメータ |
|:-----------|------------|
| URI| https://<ドメイン名>.cybozu.com/k/v1/record.json?app=<アプリ ID>&id=<レコード ID>      | 
| メソッド| GET        | 
| 受け入れる| application/xml | 
| コンテンツタイプ |  application/json|
| 要求本文| <空欄>| 
| 要求本文をエンコードします| オフ       | 

設定後のイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/86e0c26e-30d8-7a1c-3669-7df4928f4be7.png)


返却される値については、[生成された変数] の "Web サービスの応答テキスト" に設定されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/b07d4f25-f81b-3b38-6dbd-206195803bfd.png)


実行したした結果は、以下のような JSON 形式の文字列です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/13176d82-addf-0e11-605c-d5ce8a23a6fa.png)

この文字列を PAD 上で扱いやすくするために "JSON をカスタムオブジェクトに変換" アクションで、変換します。
API の実行結果が格納されている %WebServiceResponse01% を %JsonAsCustomObject01% という変数に変換します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/548e9ddf-6e91-9083-476a-8fe49ba4d304.png)

変換されたカスタムオブジェクトの内容は以下の通りの構造のデータとして確認することができるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/022dd6f4-9d78-4afa-70a4-bfc117194f90.png)

今回返却された内容は、JSON 形式が構造化されているだけですので、データ構造に直接アクセスして各アクションで使用します。例えば、取得した内容をメッセージボックスに表示する場合は、以下のように構造にアクセスして表示したい内容を設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/41e828b1-f5e2-985e-01be-750d75aee4de.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/4bd879d6-1455-8468-71c1-c0611768f486.png)



カスタムオブジェクトの内容は、フローデザイナーのフロー変数からカスタム オブジェクトの変数を表示し、詳細表示をクリックすることで、アクセスする構造を確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/6051c6fe-f59b-ce81-4838-6df1c9ffa5bc.png)


または、API の仕様を確認して上記の結果と照らし合わせると分かりやすいかもしれません。
レコードの取得（GET）

https://developer.cybozu.io/hc/ja/articles/202331474-%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E5%8F%96%E5%BE%97-GET-

### 2. レコードの登録（POST）
アプリ上に新規レコードを登録します。
"Web サービスを呼び出します" アクション必要な設定を入力します。
| プロパティ| パラメータ |
|:-----------|------------|
| URI| https://<ドメイン名>.cybozu.com/k/v1/record.json      | 
| メソッド| POST        | 
| 受け入れる| application/xml | 
| コンテンツタイプ |  application/json|
| 要求本文| ※以下にサンプル記載します| 
| 要求本文をエンコードします| オフ       |
 
``` JSON
{
    "app": "<アプリ ID>",
    "record": {
        "<フィールドコード>": {
            "value": "<フィールド値>"
        }
    }
}
```

例えば、アプリ ID が 12 のアプリに、フィールド コードが "文字列__1行_" という項目に "はじめまして、kintone" という項目を設定する場合は以下の JSON を指定します。

``` JSON
{
    "app": "12",
    "record": {
        "文字列__1行_": {
            "value": "はじめまして、kintone"
        }
    }
}
```

:::note info
フィールド コードは、kintone アプリ上から対象のフィールドの [フィールドコード] 項目から確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/b1cf9e31-37b0-5aef-04b8-739c0e93ca37.png)
:::

設定後のイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/20be381a-c56c-10a7-1808-dc1caca9a5b4.png)

実行後、返却される値については、[生成された変数] の "Web サービスの応答テキスト" (既定では、%WebServiceResponse%) に設定されます。
登録されたレコード ID の情報が確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/b0a41814-a598-9d38-4d74-2518f1cfbef8.png)

### 3. レコードの一括取得
アプリ上の複数のレコード情報を取得します。
今回はカーソルを使用して取得します。

カーソルを使用した取得については、以下の流れで取得します。
1) データ取得するアプリに対して、レコード取得用のカーソルを作成します。
2) カーソルを使用してレコードを取得します。
  カーソルのレコードを全て取得するため必要に応じてループ処理を組み込みます。
3) (必要に応じて) カーソルを削除します。

上記をフローに組み込むと以下のような実装になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/ba359adb-5fd3-0f4f-7051-5d058dc4a194.png)


#### 1) レコード取得用のカーソルの作成
"Web サービスを呼び出します" アクション必要な設定を入力します。

このアクションで、重要なポイントは以下です。
・要求本文には、取得対象となるアプリの ID とカーソルからの一回取得あたりの件数を指定します。(最大値は 500 です)

上記を踏まえた各パラメータの設定は以下の通りです。

| プロパティ| パラメータ |
|:-----------|------------|
| URI| https://<ドメイン名>.cybozu.com/k/v1/cursor.json      | 
| メソッド| POST        | 
| 受け入れる| application/xml | 
| コンテンツタイプ |  application/json|
| 要求本文| ※以下に JSON のサンプルを記載します| 
| 要求本文をエンコードします| オフ       | 

``` JSON
{
  "app": <アプリ ID>,
  "size": <後述の GET リクエスト 1 回あたりで取得するレコード数 (省略した場合の初期値は100、上限値は500)>
}
``` 

設定後のイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/39391637-fa49-2e63-720c-75e54fa3fbe6.png)

実行後、返却される値については、[生成された変数] セクションの "Web サービスの応答テキスト" に設定されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/43935837-fc78-cb0e-5e63-0c777b552228.png)

返却された値からカーソルの ID 部分を取得します。
今回は [テキストのトリミング] アクションを使用して取得返却された文字列から ID 値が出てくる文字を取得します。
「{"id":"」 と 「","totalCount"」 の間の文字列を取得するために以下のようにパラメータを設定します。
\ (バック スラッシュ) は、 " (ダブルクォーテーション) をエスケープするために設定しています。入力フィールド内で " は文字列の囲みで使用されますが、\ でエスケープすることで、ただの文字列として扱うことできます。
取得した文字列は、CroppedText という変数に格納して後述のデータ取得やカーソル削除で使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/a21e50d0-ce22-c51a-5765-451cb4001e65.png)

:::note info
他の取得方法として返却値は json なので、上記にも何回もでてきている "JSON をカスタムオブジェクトに変換" アクションで、変換して、id 項目にアクセスすることでも取得できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/d211f758-563c-55e5-5d82-0ff2bf9f9c2f.png)
:::

#### 2) カーソルを使用してレコードを取得
作成したカーソルからレコードを取得しますが、こちらも "Web サービスを呼び出します" アクションを使用します。

このアクションで、重要なポイントは以下です。
・取得対象のカーソルの ID は、HTTP のクエリ文字列として送信します。
上記を踏まえた各パラメータの設定は以下の通りです。

| プロパティ| パラメータ |
|:-----------|------------|
| URI| https://<ドメイン名>.cybozu.com/k/v1/cursor.json?id=<カーソルの ID>     | 
| メソッド| GET        | 
| 受け入れる| application/xml | 
| コンテンツタイプ |  application/json|
| 要求本文| <空欄>| 
| 要求本文をエンコードします| オフ       | 

設定後のイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/7b6b1a5c-cc99-4f53-d124-3851d598501e.png)

返却される値については、[生成された変数] の "Web サービスの応答テキスト" の変数に設定された値を "JSON をカスタムオブジェクトに変換" アクションで、変換します。
変換すると以下のように [records] というリストと [next] という True/False (Boolean 値) が格納されたパラメータが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/304a63b1-1c0e-15f8-7ddb-d0b33e15c09f.png)

[records] は、取得できたレコードがリスト型で格納されています。リスト型なので For Each などの処理で扱うことができます。また、レコード毎に処理する際のフィールドへのアクセスは **1. レコードの取得（GET）** と同じ方法でアクセスできます。
一方、[next] は、今回 GET できたレコード以上にさらにカーソルにレコードが存在している場合に True が返却されます。
カーソルでの取得は、GET 1 回あたり上限 500 レコードまでになるので、まだカーソル内に取得可能なレコードが存在する場合は True が返却され、同じカーソルに対して複数回取得処理を行った結果、レコードを取得しきった場合は False が返却されます。
具体例としてカーソル内に 2,000 レコードが存在し、1 回あたり 500 件ずつレコードを取得する場合は以下のような取得結果になるはずです。

| 回数| 取得したレコード数  | [next] の値|
|:-----------|------------|--|
| 1| 1~ 500     | True|
| 2| 501~1,000        |True |
| 3| 1,001~1,500        |True |
| 4| 1,501~2,000        |False |

つまり、カーソル内のレコードを取得しきるまで、今回のレコードを取得する処理を繰り返し実行する必要があります。
また、取得した内容を取得後にまとめて処理する必要がある場合は 1 つのリストにまとめてデータを格納することも検討します。
各アクションごとの設定詳細は割愛しますが、以下の処理で実現できることを確認しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/8d7cd6df-7539-25cc-8ee6-0553fdfeecda.png)

#### 3) カーソルの削除
使用したカーソルを削除します。
有効なカーソルの数は 1 ドメイン辺り10 のため使用したカーソルについては、必要に応じて削除します。
なお、レコードを取得しきった場合や時間経過でも自動的に削除されるそうです。
今回の実装ではカーソルのレコードを取得しきる処理のため実装不要ですが、備忘録として記載します。

このアクションで、重要なポイントは以下です。
・取得対象のカーソルの ID は、HTTP のクエリ文字列として送信します。
上記を踏まえた各パラメータの設定は以下の通りです。

| プロパティ| パラメータ |
|:-----------|------------|
| URI| https://<ドメイン名>.cybozu.com/k/v1/cursor.json     | 
| メソッド| DELETE        | 
| 受け入れる| application/xml | 
| コンテンツタイプ |  application/json|
| 要求本文|※ 以下に JSON のサンプルを記載します| 
| 要求本文をエンコードします| オフ       | 

``` JSON
{
  "id": <カーソルの ID>
}
``` 
設定後のイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547452/7112d549-08ad-63d5-a009-61296d136333.png)

返却される値については、[生成された変数] の "Web サービスの応答テキスト" の変数には値が入ってこないので、StatusCode が 200 で返却されているかを確認します。



<参考情報>
レコードの取得（GET）


https://developer.cybozu.io/hc/ja/articles/202331474


レコードの登録（POST）

https://developer.cybozu.io/hc/ja/articles/202166160

レコードの一括取得

https://developer.cybozu.io/hc/ja/articles/360029152012

カーソル API を使ってレコードを一括取得する

https://developer.cybozu.io/hc/ja/articles/360028843531-%E3%82%AB%E3%83%BC%E3%82%BD%E3%83%AB-API-%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E4%B8%80%E6%8B%AC%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B

セキュアコーディング ガイドライン

https://developer.cybozu.io/hc/ja/articles/201919400