PowerShellでOutSystemsで作ったREST APIを呼んで見る

OutSystemsで作成したExpose REST APIを、PowerShellから呼び出す方法を確認してみる。
API呼び出しには、PowerShellのInvoke-RestMethodを使う。
HTTP Responseのヘッダーを受け取るのには、PowerShell Version6.0.0以上で使える-ResponseHeadersVariableを使うので注意。

# 環境情報
Personal Environment(Version 11.21.0 (Build 39357))
Service Studio(Version 11.54.20)
PowerShell (Version 7.3.6)

```
$PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.3.6
PSEdition                      Core
GitCommitId                    7.3.6
OS                             Microsoft Windows 10.0.22621
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
```

# 手始めにGETでアクセスする方法を確認
## シンプルなGET API
### テスト対象API
REST API MethodのHTTP MethodプロパティをGETにする。

Input Parameter
| Name | Data Type | Received In |
|:-:|:-:|:-:|
| TestText | Text (Basic Types) | URL |

Output Parameter
| Name | Data Type | Received In |
|:-:|:-:|:-:|
| ResultText | Text (Basic Types) | Body |

実装内容
受け取ったTextの後ろに "_APIで編集"という文字列を追加する。

### PowerShellによるアクセス
以下のコマンドの<>で囲んでいる部分は実際の値に置き換える必要がある。
シンプルなOutput Parameterが1つだけのGETなので、Invoke-RestMethodはUriパラメータだけ指定すればよい。
``` PS
PS C:\Users\test> $Url = "https://<モジュール名>/<eSpace名>/rest/<REST API Name>/<REST API Method Name>?TestText=サンプルテキスト"
PS C:\Users\test> Invoke-RestMethod -Uri $Url
サンプルテキスト_APIで編集
```
結果を見ると、想定通り、Output Parameterは「\<Input Parameter\>_APIで編集」になっている。

## APIでBasic認証を有効にする
### APIの変更点
「シンプルなGET API」と同じメソッドを使い、REST APIのAuthenticationプロパティだけを、None -> Basicに変更する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/726bf6ed-7eb7-77bb-0405-cc5bb98076f4.png)

### PowerShellによるアクセス -> -Credentialパラメータを追加する
以下のコマンドの<>で囲んでいる部分は実際の値に置き換える必要がある。

まず、「シンプルなGET API」と同じコマンドを流してみる。
Basic認証を設定したため、認証情報を要求しないアクセスは失敗する。
``` PS
PS C:\Users\test> $Url = "https://<モジュール名>/<eSpace名>/rest/<REST API Name>/<REST API Method Name>?TestText=サンプルテキスト"
PS C:\Users\test> Invoke-RestMethod -Uri $Url
Invoke-RestMethod: {"Errors":["Basic Authentication required."],"StatusCode":401}
```

Basic認証情報を渡すには、PowerShell内でSystem.Management.Automation.PSCredentialオブジェクトを作り、-Credentialパラメータに渡す。
同時にAuthenticationパラメータにBasicを渡すが、これは省略しても大丈夫そう。

``` PS
PS C:\Users\test> $Url = "https://<モジュール名>/<eSpace名>/rest/<REST API Name>/<REST API Method Name>?TestText=サンプルテキスト"
PS C:\Users\test> $Username = "<OutSystemsにログインできるユーザーのUsername>"
PS C:\Users\test> $Password = "<OutSystemsにログインできるユーザーのPassword>"
PS C:\Users\test> $SecurePassword = ConvertTo-SecureString $Password -AsPlainText -Force
PS C:\Users\test> $Credential = New-Object System.Management.Automation.PSCredential($Username, $SecurePassword)
PS C:\Users\test> Invoke-RestMethod -Uri $Url -Authentication Basic -Credential $Credential
サンプルテキスト_APIで編集
```

# POSTでアクセスする方法を確認
## MethodをPOSTにし、Output ParameterとしてStructureを返す
### テスト対象API
REST API MethodのHTTP MethodプロパティをPOSTにする。

Input Parameter
| Name | Data Type | Received In |
|:-:|:-:|:-:|
| TestText | Text (Basic Types) | URL |

Output Parameter
| Name | Data Type | Received In |
|:-:|:-:|:-:|
| TestStructure | PSRequestTest | Body |

Structure PSRequestTestの定義は以下の通り。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/7f41b3f9-c319-0a24-f9fa-e92788e33df8.png)


実装内容
- TestStructure.TextAttribute: 受け取ったTextの後ろに "_APIで編集"という文字列を追加する
- TestStructure.DateTimeAttribute: CurrDateTime()

### PowerShellによるアクセス -> -Method, -ContentTypeパラメータを追加する
「APIでBasic認証を有効にする」のコマンドから、Invoke-RestMethod呼び出しの内容だけが変わるので、その行のみ以下に記載。
MethodパラメータでPOSTメソッドを利用することを、ContentTypeパラメータでAPIのレスポンスがJSON形式であることを指定している。

``` PS
PS C:\Users\test> Invoke-RestMethod -Uri $Url -Authentication Basic -Credential $Credential -Method POST -ContentType application/json

TextAttribute              DateTimeAttribute
-------------              -----------------
サンプルテキスト_APIで編集 2023/08/26 11:12:12
```
API呼び出しで返ってくるのがJSONである場合、Invoke-RestMethodは、PowerShellのオブジェクトであるため、上記の通り、結果がテーブル形式で表示されている。

> PSObject
> When the request returns JSON strings, this cmdlet returns a PSObject representing the data.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-restmethod?view=powershell-7.3#outputs

## APIのResponse Headerの値にアクセスしたいとき
### APIの変更点
「MethodをPOSTにし、Output ParameterとしてStructureを返す」ケースとの差分だけを記述。
Response HeaderにTestIntegerという名前で値を返す。その値は実行日時の秒の部分とする。

Output Parameter
| Name | Data Type | Received In |
|:-:|:-:|:-:|
| TestStructure | PSRequestTest | Body |
| TestInteger | Integer | Header |

実装内容
TestIntegerには、Second(CurrDateTime())を設定する。

### PowerShellによるアクセス -> -ResponseHeadersVariableパラメータを追加する
「APIでBasic認証を有効にする」のコマンドから、Invoke-RestMethod呼び出しの内容だけが変わるので、その行のみ以下に記載。

ResponseHeadersVariableパラメータには、HTTP通信のResponse HeaderのKeyと値を指定した変数に格納するもの。変数名は「$」抜きで指定する。また、PowerShell Version 6.0.0以上が必要な点に注意。

``` PS
PS C:\Users\test> Invoke-RestMethod -Uri $Url -Authentication Basic -Credential $Credential -Method POST -ContentType application/json -ResponseHeadersVariable ResponseHeaders

TextAttribute              DateTimeAttribute
-------------              -----------------
サンプルテキスト_APIで編集 2023/08/26 11:23:04

PS C:\Users\test> $ResponseHeaders

Key                       Value
---                       -----
(省略)
TestInteger               {4}
(省略)
Content-Type              {application/json; charset=utf-8}
Content-Length            {100}
Expires                   {-1}
```

## Input Parameterに複数の値を指定するとき
### APIの変更点
「APIのResponse Headerの値にアクセスしたいとき」ケースとの差分だけを記述。

Input Parameter
| Name | Data Type | Received In |
|:-:|:-:|:-:|
| TestStructure | PSRequestTest | Body |

実装内容
- TestStructure.TextAttribute: 受け取ったTextの後ろに "_APIで編集"という文字列を追加する
- TestStructure.DateTimeAttribute: 受け取ったDateTimeの日付に+1する

### PowerShellによるアクセス -> -Bodyパラメータを追加する
「APIでBasic認証を有効にする」のコマンドから、Invoke-RestMethod呼び出しの内容だけが変わるので、その行のみ以下に記載。

- $BodyにはPowerShellのオブジェクトを作ったあと、ConvertTo-JsonコマンドレットでJSON形式に変換したものをセット
- Bodyパラメータに$Bodyを渡す（これでリクエストボディにJSONが渡り、OutSystemsのExpose REST APIが想定する形式になる）
- ContentTypeパラメータに「;charset=utf-8」を追加。この際、このパラメータの値全体を""（ダブルクォート）でくくっている（おそらく「;」が""の外にあると問題になる。charsetを足すのは、リクエストボディの日本語が文字化けするのを防ぐため）。

``` PS
PS C:\Users\test> $Body = @{
>>     TextAttribute = "サンプルテキスト"
>>     DateTimeAttribute = "2023-08-26T20:34:15Z"
>> } | ConvertTo-Json
PS C:\Users\test> Invoke-RestMethod -Uri $Url -Authentication Basic -Credential $Credential -Method POST -ContentType "application/json;charset=utf-8" -ResponseHeadersVariable ResponseHeaders -Body $Body

TextAttribute              DateTimeAttribute
-------------              -----------------
サンプルテキスト_APIで編集 2023/08/27 20:34:15
```