Power Automate for desktop「node.jsとjson-serverでお手軽テスト環境をつくる」

# 概要

Power Automate for desktop で API を叩くフローを作成する際、テスト環境が必要になることがあります。その際、Node.js と json-server を使ってお手軽にテスト環境を構築する方法を紹介します。json-server は、json ファイルを使って簡単に REST API を立ち上げることができるツールです。Node.js は、JavaScript の実行環境で、json-server を動かすために使用します。

# 環境

- Windows 11 Pro 23H2
- Power Automate for desktop 2.46.263.24194 インストーラー版
- [Node.js](https://nodejs.org/en) v20.16.0(2024 年 8 月 15 日時点 LTS インストーラー版)
- [json-server](https://github.com/typicode/json-server/tree/v0)@0.17.4
- [Visual Studio Code](https://code.visualstudio.com/) 1.92.1

# 注意事項

- 本記事は Power Automate for desktop のフロー作成に慣れている方を対象としています
- json-server の詳細な使い方は[公式ドキュメント](https://github.com/typicode/json-server/)をご確認ください
- [Visual Studio Code](https://code.visualstudio.com/)のインストール方法は省略しますのであらかじめインストールしておいてください
- 執筆（2024 年 8 月 15 日)時点での情報です。最新の情報は公式ドキュメントをご確認ください)
- 本記事には個人的な見解が含まれる場合がありますが、ご了承ください
- 自己責任でお願いいたします

# 手順

1. Node.js のインストール
   [Node.js](https://nodejs.org/en)の公式サイトから[インストーラー](https://nodejs.org/en/download/prebuilt-installer)をダウンロードし、インストールします。完了したら、PowerShell を開いてバージョンを確認します。
   ```powershell
    node -v
   ```
   バージョンが表示されればインストール完了です。
2. json-server のインストール
   テスト環境用のフォルダを作成します。フォルダ階層は任意にしてください。ここでは Documents フォルダに json-server フォルダを作成しました。

   ```powershell
     mkdir json-server
   ```

    ![alt mkdir](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/6e0e4959-ac13-ecbc-07a6-0d7f660286a9.png)
   作成したフォルダに移動します。

   ```powershell
     cd json-server
   ```

   PowerShell を開いて以下のコマンドを実行します。

   ```powershell
    npm install json-server@0.17.4
   ```

   インストールが完了したら、以下のコマンドを実行してバージョンを確認します。

   ```powershell
    npx json-server -v
   ```

   バージョンが表示されればインストール完了です。

3. json ファイルの作成

   そのままPowerShelからlVisual Studio Code を開きます。
    ```powershell
       code .
   ```
   json-server フォルダに db.json ファイルを作成します。ファイル名は任意で構いませんが、ここでは db.json とします。ファイルに以下の内容を記述します。

   ```json
   {
     "employees": [
       { "id": 1, "name": "John Doe", "age": 30 },
       { "id": 2, "name": "Jane Doe", "age": 25 }
     ]
   }
   ```

4. json-server の起動
   Visual Studio Code のターミナルを開いて以下のコマンドを実行します。

   ```powershell
    npx json-server --watch db.json
   ```

   以下のメッセージが表示されれば起動完了です。

   ```powershell
    \{^_^}/ hi!

    Loading db.json
    Done

    Resources
    http://localhost:3000/employees

    Home
    http://localhost:3000
   ```

5. 確認
   ブラウザを開いて、`http://localhost:3000/employees` にアクセスします。以下の内容が表示されれば成功です。
   ```json
   [
     {
       "id": 1,
       "name": "John Doe",
       "age": 30
     },
     {
       "id": 2,
       "name": "Jane Doe",
       "age": 25
     }
   ]
   ```
   また`http://localhost:3000/` にアクセスすると使用できるエンドポイントとメソッド、ドキュメントへのリンクなどが表示されます。
   1. Power Automate for desktop で API を叩く
   Power Automate for desktop を開いて、新しいフローを作成します。HTTP リクエストを送信するアクションを追加し、URL に`http://localhost:3000/employees` を指定します。メソッドは GET を選択します。フローを実行すると、json-server が返すデータを取得できます。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/cd96d176-faff-e764-b0f6-a37e435ec685.png)

   2. id を指定して取得
   URL に`http://localhost:3000/employees/`1 または `http://localhost:3000/employees/?id=1` を指定すると、id が 1 のデータを取得できます。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/37207a29-ff66-9a51-d3fa-b000410a3404.png)
   3. 準備完了です。
   ctrl+c で json-server を停止します。json-server を再度起動する際は、json-server フォルダに移動して、`npx json-server --watch db.json` を実行します。

# テスト環境ができたのでフローに応用してみよう

このテスト環境を使って、Power Automate for desktop で API を叩くフローを作成してみましょう。
今回のお題は API に１回のリクエストで取得できるデータ数が制限されている場合の対応を考えます。例えば、API に１回のリクエストで取得できるデータ数が 7 件までと制限されている場合、全データを取得するためには複数回リクエストを送信する必要があります。このような場合、ページング処理を実装する必要があります。ページング処理を実装することで、複数回リクエストを送信して全データを取得することができます。

サンプルデータは生成 AI を使って作成しました。サンプルファイルは[こちら](https://github.com/ZeroSysLog/samples)から db.json をダウンロード可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/e078467a-f90d-e21a-5fcc-19b2fb9e6802.png)

以下の手順でフローを作成します。

db.json をダウンロード後、json-server フォルダに保存します。
json-server を起動します。

```powershell
  npx json-server --watch db.json
```

起動すると２つのエンドポイントが使用できるようになります。

- `http://localhost:3000/metaData`
- `http://localhost:3000/order`

## 1.  metadata にある total と limit を取得しページング処理に必要なループ回数を計算します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/01711c73-ccd1-79be-9090-322f8003dc21.png)
以下の手順でページング処理を考えます。

### ページング処理における切り上げの必要性

ページング処理では、全データ数（Total）を1回のリクエストで取得可能なデータ数（Limit）で割ることで、必要なリクエスト回数を算出します。しかし、この除算の結果が整数にならない場合があるため、切り上げが必要になります。

#### なぜ切り上げが必要か

1. データの取りこぼしを防ぐ：
   切り捨てると、最後のページのデータが取得できなくなる可能性があります。例えば、20件のデータを7件ずつ取得する場合、20 ÷ 7 = 2.857... となりますが、これを切り捨てて2回のリクエストだけでは、最後の6件のデータが取得できません。

2. 端数の処理：
   データ総数がLimitで割り切れない場合、最後のページには残りのデータが含まれます。この最後のページを確実に取得するために、切り上げが必要になります。

3. プログラムの簡素化：
   切り上げることで、「もし最後のページがある場合は追加でリクエストを送る」といった条件分岐を避けられます。標準アクションの切り下げで実装も可能ですが、余りが0の場合はループ回数を減らす条件分岐が必要になります。

#### 具体例

- Total = 20, Limit = 7 の場合：
  20 ÷ 7 ≈ 2.857...
  切り上げて3回のリクエストが必要。
  (1回目: 7件, 2回目: 7件, 3回目: 6件)

- Total = 20, Limit = 5 の場合：
  20 ÷ 5 = 4
  ちょうど4回のリクエストが必要。

- Total = 20, Limit = 9 の場合：
  20 ÷ 9 ≈ 2.222...
  切り上げて3回のリクエストが必要。
  (1回目: 9件, 2回目: 9件, 3回目: 2件)

このように、切り上げることで、どのような総数とLimit の組み合わせでも、確実に全てのデータを取得することができます。

### Power Automate for desktopでの実装

Power Automate for desktopには標準アクションでは切り上げ機能がないため、PowerShellスクリプトを使用して以下のように実装します：

```powershell
[int][Math]::Ceiling(%Total% / %Limit%) - 1
```

ここで `-1` をしているのは、ループのインデックスが0から始まるためです。これにより、必要なループ回数を正確に計算できます。

PowerShell スクリプトの実行アクションの出力は文字列となるため数値に変換します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/52ccd9fa-836f-573d-2fcb-6ff06e4b5a11.png)

## 2. ループ処理を実装し取得したデータをカスタムオブジェクトとして%OutputList%に統合して出力します。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/c8925e5a-517c-c0e5-f035-667590ee7ade.png)
- 空のリスト変数%OutputList%を先に作成しておきます。 - json-server の order エンドポイントにパラメーター`_start`と`_limit`を指定してリクエストします。
-  `?_start=%LoopIndex * Limit%`とすることで、ループごとに取得するデータの開始位置をオフセットできます。
-  `&_limit=%Limit%`とすることで、取得するデータの件数を指定します。
  

   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/0cf266d7-88a5-a3bc-3eb3-ebc4e087273d.png) 
   - JSON 形式のデータを取得したら、カスタムオブジェクトに変換します。カスタムオブジェクトに変換することで、Power Automate for desktop でデータを扱いやすくなります。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/f8a8a1c0-4ce1-5bbc-0751-43a144db691a.png)
   - ループのごとにリストカスタム オブジェクトを再帰的に統合します。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/b179176b-b26c-3592-4db9-bd1642ae4f0e.png)
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/2bf7deb4-f1cb-d0f0-5b47-897e653dcca9.png)

```r
/# ######################################
1リクエストでのデータ取得件数制限にあわせてページングし
全データを取得します
#######################################/
**REGION metadataエンドポイントからtotalとlimitを取得してページングするためのループ回数%PagingLoopCount%を決定
Web.InvokeWebService.InvokeWebService Url: $'''http://localhost:3000/metaData''' Method: Web.Method.Get Accept: $'''application/json''' ContentType: $'''application/xml''' ConnectionTimeout: 30 FollowRedirection: True ClearCookies: False FailOnErrorStatus: False EncodeRequestBody: True UserAgent: $'''Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.21) Gecko/20100312 Firefox/3.6''' Encoding: Web.Encoding.AutoDetect AcceptUntrustedCertificates: False Response=> MetaDataAPIResponse StatusCode=> MetaDataStatusCode
Variables.ConvertJsonToCustomObject Json: MetaDataAPIResponse CustomObject=> MetaDataCustomObject
SET Limit TO MetaDataCustomObject['limit']
SET Total TO MetaDataCustomObject['total']
/# ######################################
ページング回数の計算 totalをlimitで除算して切り上げてから1を引く
#######################################/
@@copilotGeneratedAction: 'False'
Scripting.RunPowershellScript.RunPowershellScript Script: $'''[int][Math]::Ceiling(%Total%/ %Limit%)-1''' ScriptOutput=> PowershellOutput
Text.ToNumber Text: PowershellOutput.Trimmed Number=> PagingLoopCount
**ENDREGION
**REGION orderエンドポイントからページングしながらデータを取得しリスト カスタムオブジェクト OutputListにまとめる
Variables.CreateNewList List=> OutputList
LOOP LoopIndex FROM 0 TO PagingLoopCount STEP 1
    Web.InvokeWebService.InvokeWebService Url: $'''http://localhost:3000/order?_start=%LoopIndex * Limit%&_limit=%Limit%''' Method: Web.Method.Get Accept: $'''application/json''' ContentType: $'''application/xml''' ConnectionTimeout: 30 FollowRedirection: True ClearCookies: False FailOnErrorStatus: False EncodeRequestBody: True UserAgent: $'''Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.21) Gecko/20100312 Firefox/3.6''' Encoding: Web.Encoding.AutoDetect AcceptUntrustedCertificates: False Response=> OrderDataAPIResponse StatusCode=> OrderDataStatusCode
    Variables.ConvertJsonToCustomObject Json: OrderDataAPIResponse CustomObject=> OrderDataCustomObject
    Variables.MergeLists FirstList: OutputList SecondList: OrderDataCustomObject OutputList=> OutputList
END
**ENDREGION
```

# まとめ

json-server を使ってお手軽にテスト環境を構築する方法を紹介しました。Power Automate for desktop で API を叩くフローを作成する際、テスト環境が必要になることがあります。json-server は、json ファイルを用意するだけで簡単に REST API を立ち上げることができます。GET 以外のメソッドも使えるので複雑な処理を試すのに便利です。ぜひお試しください。