MoreBeerMorePower

Power Platform中心だけど、ノーコード/ローコード系を書いてます。

Azure API Management で Project Oakdale 環境にカスタムコネクターを追加する

Microsoft Teams に Power Apps の機能が追加 (パブリックプレビュー) された際に同時にアナウンスされた Azure API Management からのカスタムコネクター作成 について、Google Books APIを例として紹介します。

該当するDocsは以下

docs.microsoft.com

Azure API Management 由来のカスタムコネクターは既存のTeamsライセンスの範囲で利用可能 ということで注目されているアップデートです。ただし Azure API Management 自体にはプランに応じた課金が発生する点に注意してください。

各プランの価格については以下のページで確認できます。注意するのは、CONSUMPTION とそれ以外で課金単位が異なることです。CONSUMPTION はAPIがコールされる回数に依存しますが、他のプランでは1時間当たりXX円となっています。忘れて有効にしたままだと 平気で月数万~数十万円飛びます。 個人で利用する際にはCONSUMPTIONにしておくことをお勧めします。

azure.microsoft.com

この投稿では、Azure API Managementのリソース作成からはじめて、Google Books API をPower Apps から実行するところまでの手順をカバーします。ただしGoogle Books API側については割愛しますので、Qiitaなどで他の方のブログを参照してください。

1. Azure API Management リソース作成

まずは Azure API Management のリソースを Azure Portal で作成します。Azure Marketplaceで「API Management」と検索して、リソースの作成を開始します。

f:id:mofumofu_dance:20201104115228p:plain

基本設定では、以下のように設定しました。この際、Resource name はサーバーURLになるので、他のテナントのリソースも含めて一意である必要があります。 また、Pricing Tierを変更することを忘れない ようにしましょう。

設定項目 設定値
Region Japan East
Resource name hiro-apim-test *ご自身で一意なものを探してください
Organization name Hiro Personal
Administrator email xxxxx@xxxx.com
Pricing tier Consumption

f:id:mofumofu_dance:20201104121030p:plain

他の設定項目 (モニタリングやネットワークなど) はここではデフォルトのままにしています。必要に応じて Application Insight や 各種プロトコルのON/OFFを行ってください。

設定内容を確認し、問題なければ「Create」をクリックしてリソースを作成します。

f:id:mofumofu_dance:20201104120445p:plain

2. Google Books API を追加

2-1. API追加

ここから、作成した API Management のリソースにAPIを追加していきます。

左側のメニューから 「APIs」>「Add API」>「Blank API」と進みます。

f:id:mofumofu_dance:20201104130007p:plain

API 作成情報のポップアップが表示されます。今回の例であるGoogle Books APIに合わせて、まずは以下のように設定します。

設定項目 設定値
Display name GoogleBooks
Name googlebooks
Web service URL https://www.googleapis.com/books/v1
API URL suffix booksearch

f:id:mofumofu_dance:20201104130455p:plain

この段階で APIのBase URLが決定しますが、先ほどリソースを作成した際のResource name がサーバーURLになっていることがわかります。

Display nameや suffixは管理しやすいように決定してください。これでAPIのガワが出来上がります。まだ操作を定義していないのでこのURLにリクエストを送っても特に何もおこりません。

2-2. 検索処理追加

次に本の検索処理であるVolumes:list を追加します。

追加した「GoogleBooks」を選択して「Add operation」をクリックすると追加する処理に関する設定が表示されます。

ここで指定するのはGoogle Books APIの Volumes:listに特有な部分なので、それぞれ以下のように設定します。

設定項目 設定値
Display name VolumeList
Name volumelist
メソッド GET
URL volumes

f:id:mofumofu_dance:20201104131445p:plain

最後に追加した「volumes」が、API作成時に指定した Web service URL と合わさって、Google Books APIの本の検索処理に対するURL になります。 (https://www.googleapis.com/books/v1/volumes)

続いて検索のためのクエリパラメーターとレスポンスの定義をしていきます。

f:id:mofumofu_dance:20201104132558p:plain

Google Books API では q={search terms}で検索を実行するので、クエリパラメーターに qを追加しておく必要があります。

「Add parameter」で枠を追加して、以下のように設定します。

設定項目 設定値
NAME q
DESCRIPTION search term
TYPE string
REQUIRED true (チェック)

f:id:mofumofu_dance:20201104132825p:plain

レスポンス設定で行うことはスキーマ定義です。

「Add response」をクリックし、「200 OK」を選択したのち、「Add representation」で枠を追加、CONTENT TYPEapplication/jsonとします。

f:id:mofumofu_dance:20201104150046p:plain

DEFINITIONではドロップダウンから「New definition」を選ぶとスキーマ定義のためのポップアップが表示されます。 Google BooksのVolume:list のレスポンスに従い、以下を設定してください。

{
    "type": "object",
    "properties": {
        "kind": {
            "type": "string"
        },
        "totalItems": {
            "type": "integer"
        },
        "items": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "kind": {
                        "type": "string"
                    },
                    "id": {
                        "type": "string"
                    },
                    "etag": {
                        "type": "string"
                    },
                    "selfLink": {
                        "type": "string"
                    },
                    "volumeInfo": {
                        "type": "object",
                        "properties": {
                            "title": {
                                "type": "string"
                            },
                            "authors": {
                                "type": "array",
                                "items": {
                                    "type": "string"
                                }
                            },
                            "publishedDate": {
                                "type": "string"
                            },
                            "description": {
                                "type": "string"
                            },
                            "industryIdentifiers": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "properties": {
                                        "type": {
                                            "type": "string"
                                        },
                                        "identifier": {
                                            "type": "string"
                                        }
                                    },
                                    "required": [
                                        "type",
                                        "identifier"
                                    ]
                                }
                            },
                            "readingModes": {
                                "type": "object",
                                "properties": {
                                    "text": {
                                        "type": "boolean"
                                    },
                                    "image": {
                                        "type": "boolean"
                                    }
                                }
                            },
                            "pageCount": {
                                "type": "integer"
                            },
                            "printType": {
                                "type": "string"
                            },
                            "maturityRating": {
                                "type": "string"
                            },
                            "allowAnonLogging": {
                                "type": "boolean"
                            },
                            "contentVersion": {
                                "type": "string"
                            },
                            "panelizationSummary": {
                                "type": "object",
                                "properties": {
                                    "containsEpubBubbles": {
                                        "type": "boolean"
                                    },
                                    "containsImageBubbles": {
                                        "type": "boolean"
                                    }
                                }
                            },
                            "imageLinks": {
                                "type": "object",
                                "properties": {
                                    "smallThumbnail": {
                                        "type": "string"
                                    },
                                    "thumbnail": {
                                        "type": "string"
                                    }
                                }
                            },
                            "language": {
                                "type": "string"
                            },
                            "previewLink": {
                                "type": "string"
                            },
                            "infoLink": {
                                "type": "string"
                            },
                            "canonicalVolumeLink": {
                                "type": "string"
                            }
                        }
                    },
                    "saleInfo": {
                        "type": "object",
                        "properties": {
                            "country": {
                                "type": "string"
                            },
                            "saleability": {
                                "type": "string"
                            },
                            "isEbook": {
                                "type": "boolean"
                            }
                        }
                    },
                    "accessInfo": {
                        "type": "object",
                        "properties": {
                            "country": {
                                "type": "string"
                            },
                            "viewability": {
                                "type": "string"
                            },
                            "embeddable": {
                                "type": "boolean"
                            },
                            "publicDomain": {
                                "type": "boolean"
                            },
                            "textToSpeechPermission": {
                                "type": "string"
                            },
                            "epub": {
                                "type": "object",
                                "properties": {
                                    "isAvailable": {
                                        "type": "boolean"
                                    }
                                }
                            },
                            "pdf": {
                                "type": "object",
                                "properties": {
                                    "isAvailable": {
                                        "type": "boolean"
                                    }
                                }
                            },
                            "webReaderLink": {
                                "type": "string"
                            },
                            "accessViewStatus": {
                                "type": "string"
                            },
                            "quoteSharingAllowed": {
                                "type": "boolean"
                            }
                        }
                    },
                    "searchInfo": {
                        "type": "object",
                        "properties": {
                            "textSnippet": {
                                "type": "string"
                            }
                        }
                    }
                }
            }
        }
    }
}

ここまでで一度「Save」ボタンを押して保存しておきます。

下図のような表示になっていることを確認してください。

f:id:mofumofu_dance:20201104150747p:plain

2-3. APIキーの設定

Google Books APIでは不要ですが、他のAPIを実行する場合のために、APIキー (というか認証情報)の追加方法を残しておきます。

ここでは外部サービス利用のための認証情報はAPI Managementで持って、ユーザーには入力させないこととします。

Googleの各種APIでは、クエリパラメーターにAPI Keyを設定することで認証できるので、このクエリパラメーターを API Management側で追加します。

先ほどの画面で「Inbound processing」のブロックにある「Add policy」をクリックします。 すぐにどのようなポリシーを設定するのかを選択する画面に切り替わりますので、一覧の中から「Set query parameters」を選択します。

あとはGoogle のコンソールから取得したAPIキーを入力して完了です。

他のサービスでもヘッダーに Authorization : Bearer トークン を追加するパターンも同様で、「Set headers」から追加してください。

f:id:mofumofu_dance:20201104154443p:plain

2-4. 接続テスト

ここまでで作成したAPIを実行できるか、Postman等のクライアントを使いテストしてみます。

テストする際にはAPI実行のための API Management側で管理しているキーが必要になります。

リソースの左側のメニューから「Subscriptions」を選び、一番右の[...]から「Show/hide keys」でキーをコピーします。

Postmanからのリクエスト時には、Ocp-apim-Subscription-Key : コピーしたキー の形式でヘッダーを追加することでリクエストが受け付けられます。

f:id:mofumofu_dance:20201104162354p:plain

3. Power Platform へのエクスポート とコネクター設定

3-1. コネクターのエクスポート

ここまで来たらあとはPower Platform (Project Oakdaleの環境) にコネクターをエクスポートするだけです。

作成した「GoogleBooks」APIの[...]で表示されるメニューから「Export」をクリックします。エクスポート方法を選択する画面に切り替わるので、「Power Apps and Power Automate」を選択します。

画面右側にエクスポート先の環境選択と、カスタムコネクターの名前を指定するボックスが表示されますので、Teamsと関連づいている環境を選択してエクスポートを実行してください。

f:id:mofumofu_dance:20201104163450p:plain

3-2. カスタムコネクターへのセキュリティ情報追加

このセクションの設定は 2020/11/18に不要になりました。

Dataverse for teamsのリリースに伴って変更されたのだと思われます。

現在はAPIM経由のカスタムコネクターについてはPremiumマークも消えています。

f:id:mofumofu_dance:20201119095532p:plain

----以下ふるい内容だけど普通の環境に追加したときは必要なので残します。----

エクスポートしたカスタムコネクターは、Power Automate で対象の環境を開くことで確認できます。 このままでは Postmanでのテストのときに付与したヘッダー情報が追加されていないので、コネクターをアプリ・フローに追加してもUnauthorizedになってしまいます。

そこで、カスタムコネクターのセキュリティ設定を変更することでSubscription keyを入力できるようにします。

f:id:mofumofu_dance:20201104164428p:plain

カスタムコネクター一覧を表示し、対象のコネクターの🖊マークで編集を行います。

下図の数字の通り、まずは「2. Security」を表示し、「Authentication type」を編集、デフォルトでパラメータ名には、Ocp-apim-Subscription-Keyが入っているので、このまま「Update connector」をして編集を完了します。

f:id:mofumofu_dance:20201104164832p:plain

これでカスタムコネクターの修正は完了です。あとは他のコネクターと同様に、アプリやフローに追加する際にSubscription keyを入力してください。

f:id:mofumofu_dance:20201104165137p:plain

おわり

以上でAzure API Managementのリソース作成、API追加、Power Platform へのエクスポートは完了です。

他にも様々なAPIをここで管理すれば Power Platformとしては 追加料金なく各種APIを実行可能になります。(もちろん3rd Party APIだけでなく、Azure FunctionsやLogic Appsなども)

今後Project OakdaleのGAとともに注目される機能だと思いますので、ぜひこの機会に試してみてください。

最後に、API Managementは個人で利用する際にはCONSUMPTIONにしておくことをお勧めします!!

※カスタムコネクター追加後は、Google Books APIで蔵書管理などができるかと思います。先人のブログを参考にしてみてください。

mokudai.jp