Dataverse for Teams環境からプラン内でAzureFunctionsを呼び出す

Dataverse for Teams環境からカスタムコネクタを使ってAPI Management経由で自前のAzure Functionsを呼び出す方法の覚え書きです。

:::note warn
この記事の方法は古いやり方です。
現在はもっと簡単になっています。
https://docs.microsoft.com/ja-jp/azure/api-management/export-api-power-platform
:::



# 概要
- PowerAppsでカスタムコネクタを使って自前/外部APIを呼び出す場合、有償プランかコミュニティプランが必要です。
- ただし、Dataverse for Teams環境であればfor Office365プランでもAzure API Managementを経由してAPIに接続可能です。
- 個人の検証用としてAzureの各サービスは従量課金プランで作成しているので無料枠の範囲内で実現できました。

https://docs.microsoft.com/ja-jp/azure/api-management/export-api-power-platform

https://powerapps.microsoft.com/ja-jp/blog/azure-api-management-connector-on-the-power-platform/

# 手順
1. AzureFunctionsにAPIを発行する。
1. API ManagementにFunctionsAPIをインポートする
1. API Managementでテストを実行して定義を作成する
1. API ManagementからPowerAppsのコネクタをエクスポートする
1. PowerAppsのコネクタを修正する
1. PowerAppsからコネクタを呼び出す 



## Azure FunctionsにAPIを発行する
詳細は割愛します。
Azure上から空の関数アプリを作成しておき、VisualStudioなどお好きな環境、お好きな言語でFunctionsAPIを作成して発行します。
AuthorizationLevelはFunctionにしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/fc85793f-882a-ab18-803c-95fff7c83e75.png)

発行された関数
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/2e3de800-edd2-1bbc-f5a7-6041200e3682.png)

今回のリクエスト、レスポンスの例は以下のようなものです。
PowerAppsで塗り絵アプリを作るため、画像とペン入力画像を合成するAPIのつもりです。

```json:リクエスト
Content-type:application/json
{
    "image_fg_datauri":"data:image/png;base64,iVBORw0KGgoAAAmM～",
    "image_bg_datauri":"data:image/png;base64,iVBORw0KGgoAAAAN～",
    "crop_fg_image":"true",
}
```

```json:レスポンス
Content-type:application/json
{
"data":"data:image/png～"
}
```


## API ManagementにFunctionsAPIをリンクする
こちらはMSLearnに沿ってやると分かりやすいです。
https://docs.microsoft.com/ja-jp/learn/modules/build-serverless-api-with-functions-api-management/1-introduction

- 先程の関数アプリの画面に移動し左のブレード→APIセクション→API Managementを選択する<br>
- API Managementリソースの新規作成を行う。
    - 価格レベルは従量課金プランを選択します。日本リージョンでは利用できないので東アジアリージョンで。<br>
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/b66eec44-733c-2182-bfe0-cbf266b0e943.png)<br>
- デプロイに時間がかかるので待機し完了するとインスタンスにリンクされている表示がでる。<br>
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/0ee108b0-fac7-65e6-2a55-33bfeebed10b.png)<br>
- 「APIをリンク」をクリックしてリンクするAPIを選択。
- リンクが完了したら、API Managementの画面に移動します

## API Managementでテストを実行して定義を作成する
これはAPI Managementサービスの画面からやったほうが操作しやすかったです。
リンクされたAPIをテストして、リクエストやレスポンスの定義を作成します。

- サービス画面から先程作成したリソースを開きます。
- API→関数アプリ名(先程リンクした)の画面を開きます。
- 今回はPOSTメソッドしか使わないのでそれ以外のメソッドは…から削除しておきます。
- POSTメソッドのAPIをクリックして設計画面を開きます。
- Frontendは空白で詳細な定義がまだ追加されていない状態です。
- ここで一旦テストを行います。Testタブに移動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/9a3e9d90-512f-8028-3ea9-0c92a1629396.png)
- HeaderやRequestbodyに値を入れて、テストを通過させます。<br>
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/bce67692-4f76-13f6-44de-17c43b93dac7.png)

- 成功したら、テスト画面のRequestBodyとResponseBodyの右上の「Generate definition」をクリックして定義を作成します。
- 「Save as definition for this request?」にチェックを入れ、「CreateDefinition」をクリックして定義を作成します。<br>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/448fcf4d-3fb9-8151-b1b1-ff72364455a0.png)

Designタブに戻り、以下のような感じで定義が反映されているか確認します。<br>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/58bb2aee-3a83-a10f-8e7e-dc63f42e6c32.png)

- ▽で「Form-based editor」を開いてHeaders、Request、Responsesが正しく設定されているか確認しておきます。
- Headersは反映されないので自分でContent-Type等を設定してSaveをクリックします。
- 後はお好みでAPIのコール数制限などインバウンドポリシーを設定します。

## API ManagementからPowerAppsのコネクタをエクスポートする
これは簡単です。
APIs→Exportをクリックして、「PowerApps and Automate」を選択し、任意のDataverse for Teams環境にエクスポートします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/926d0869-6d2c-52e8-3c16-95f3a810283c.png)


## PowerAppsのコネクタを修正する
エクスポート先の環境でカスタムコネクタ一覧を見ると、先程エクスポートしたコネクタが表示されています。
APIのサブスクリプションキーなどを設定する必要があるため編集をクリックして修正します。

### セキュリティの設定
APIキーのパラメータ名を「subscription-key」、パラメータの場所を「クエリ」にします。
※ヘッダにするとなぜかキーを設定する画面がでてきませんでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/fae2a1b6-a492-5993-3faa-8fe62c747046.png)

>既定のヘッダー名は Ocp-Apim-Subscription-Key で、既定のクエリ文字列は subscription-key です。

### 定義の修正
「アクション」で、不要なメソッド・関数を取り込んでしまった場合は削除します。
リクエスト情報やレスポンス情報がきちんと反映されているか確認しておきます。
修正が完了したらコネクタを更新します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/71cf71c6-3673-7b5d-fa87-5c52d09f5694.png)

### テスト
APIキーが必要になるので取得してきます。
API Management→リソース→サブスクリプションで、キーの表示をクリックして主キーをコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/1be54700-5e20-4468-22f7-4e17b5494f93.png)

テスト画面に戻り「新しい接続」をクリックして接続情報を作成します。
APIキーを入力する画面が表示されるので入力します。
※この画面で入力してテストしても、何故か401(認証エラー)が返されることがあるので、その場合は接続一覧画面から接続を編集し、再度サブスクリプションキーを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/d4eb8aa6-a940-6ac9-9cba-860e4a0dd32d.png)

テスト画面に戻ってテストを実行します。
関数の仕様通り結果が返されればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/be7ddf23-d33c-a1b0-ade8-e95901579786.png)


## PowerAppsからコネクタを呼び出す
TeamsのPowerAppsは誤って戻るボタンを押してしまって発狂するので嫌いなのですが、
PowerApps側でコネクタを追加して使用するだけです。
※最近ソリューションから編集できなくなったという・・

以下は背景画像とペン入力を合成して塗り絵をするサンプルアプリです。
保存ボタンを押すとAPIを呼び出して合成します。
![PowerNurieApp.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/47ff6079-777e-3699-5031-60d99ed0eb8d.gif)


# その他
- 従量課金につき、初回のインスタンス起動時は数秒ほどもたつきます。 職場の本番環境で使ったりしたら文句がでるかな。
- 今回はAPIがアクセスキーによる認証なのでAPIM含め、URLやアクセスキーがばれるとつつかれてしまいます。
※よほどのことがない限り大丈夫だと思いますが
- 次回はAzureADでAPIを保護してみたいと思います。