【 Azure 】 Function App をインポートした API Management のトラブルシューティング方法

タイトルの通り、Azure Function App をインポートした API Management で API 実行時に **404 Not Found** が返ってくる場合のログの追跡方法と解決策について、実際の画面出力を元に、ご紹介できればと思います。

# 実現したかったこと
Azure API Management へ Function App をインポートして API として公開する。下図では、Azure Web App から API Management へリクエストが行われていますが、本記事では API Management の TEST タブより、リクエストを実行して検証を行いました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/9652e9ff-bda0-7050-6fa2-1fcbe0af1602.png" width="700">

# 開発環境
- Azure Functions Core Tools 4.0.4426
- VSCode 1.71.0
- Azure CLI 2.40.0

# 発生した事象
Azure Function App を API Managment へリンク (インポート) 後、API Gateway 経由で API を実行したところ、404 Not Found エラーが発生する。

# 試したこと

## 仮説① - Azure Function App の Functions が正常動作していない？
発生した事象から API Gateway 経由だと、API が正常動作しないということが判明したので、一度 Function App 内の各 Functions を Azure Portal 上からテストすることにしました。

対象の Function App リソースを開き、ナビゲーションメニューより、**関数 > 関数** を選択します。関数一覧が表示されるので、テストを実行したい関数を選択します。今回は GET リクエストをすると、JSON を返却する API ( HTTPTrigger ) をテストしたいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/f762d6f0-652d-d40b-b7b9-6a41a96c784a.png)

テスト対象の関数ページに遷移後、ナビゲーションメニューより **Developer > コードとテスト** を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/ec89c25f-d851-33ae-a79e-a4f0733a93df.png)

**コードとテスト** ページに遷移したら、**テストと実行** タブをクリックします。今回テストを実行する API は、検証のため ``bindngs.authLevel``を ``anonymous`` に設定しています。(デフォルト設定では、``function`` になっているはずです) ``bindings.authLevel`` については、後述します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/7fa4c742-b5aa-31e2-28e5-4e668fb8c31a.png)

関数をテスト実行する際の HTTPメソッドとキーを選択して、**実行ボタン** を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/5b73bcda-8458-09a4-5840-bef448316e0c.png)

テスト実行後、正常動作していれば、HTTP応答コード ``200 OK`` が返却されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/a5a9f5cc-fefb-e66a-dcc9-1a783df9af31.png)

という訳で、Function App 内の Functions の問題ではないということが分かりました。

## 仮説② - API Managment でのテスト時に API 認証キーが設定されていない？

さきほど紹介したように、Function App 内の関数には、``function.json`` で ``bindigs.authLevel`` を設定する必要があります。この ``authLevel`` では、関数実行時の承認レベルを設定することができます。

``authLevel`` の設定値で、関数を実行時に必要となる API キーが異なります。3種類の承認レベルが存在し、各レベルごとに実行時に求められる承認キー (APIキー) が異なります。

｜レベル | 説明 |
| --- | --- |
| anonymous | 関数実行時に APIキー は必要ありません |
| function | 関数固有の APIキー が必要です (デフォルト値) |
| admin | マスターキーが必要になります。 |

``authLevel`` を ``anonymouse`` に設定変更し、API Gateway 側からテストを実行してみましたが、同様に 404 Not Found が返ってきました。エラー内容は 404 Not Found なので、当然の結果ではあるのですが... ログをしっかりと確認しましょう。

## 仮説③ - API Gateway 側の Backend 設定が間違えている？

ここで実現したかったことで記載している図を書いてみました。API Management のテストタブで実行しているため、確実に API Gateway にはリクエストが届いている。Inbound ポリシーにも、リクエストを遮断する設定はない。となると、API Gateway から Function App への リクエストURL に誤りがあるのでは？という仮説にいきつきました。しっかり読んでいたら、最初からこの仮説が立てられたのですが、API Management と Function App への理解が不明瞭だったため、少し時間がかかってしまいました。

まず、API Management のテストタブを使って、さきほどの API をログトレースします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/73703d6c-271b-7475-99c4-d193dca05926.png)

send ではなく **Trace** ボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/8fdafff3-11a5-9a64-f9ad-ef28f2be7410.png)

Inbound -> Backend -> Outbaound のフェーズごとに、ログを確認することができるので、**Backend** を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/4282d32a-117c-e389-6a0f-9eb64124cde6.png)

API Gateway がテスト実行のリクエストを処理して、バックエンド (Function App) へどのようなリクエストを forward しているのかを確認することができます。

**Backend service URL was changed.** というメッセージと共に、Backend ランタイムURL の Prefix (URL末尾の/以下) が ``/a`` になっていることが分かります。Function App の Prefix は ``host.json`` で設定することができるのですが、何も設定していない場合、``/api`` になります。もちろん、自分で ``/a`` を設定した記憶がないので、あれ、おかしいぞとここで気付きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/0862ed71-fd39-4067-adde-7b168b10ea15.png)

検証用に関数の承認レベル (``authLevel``) を ``anonymouse`` に設定しているため、ブラウザで変更後の URL を実行してみると、ページが見つかりません。試しに、Function App の標準の Prefix である ``/api`` に変更して、再度実行してみると、Web ブラウザ経由で JSON が返却されることが確認できました。

ということで、この Backend URL がどこで設定されるかについて紹介していきます。

まず、Function App をリンクした API Management リソースへ Azure Portal 上からアクセスします。ナビゲーションメニューより、**APIs > Backend** を選択し、対象のバックエンド画面へ遷移します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/a921ea57-79b2-287e-1b4b-20b00dd40cce.png)

概要ページから、さきほどログトレースで出力されていた Prefix が ``/a`` になっているランタイムURL を見つけることができました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/3ab597db-6502-88f2-f8a6-162e5e264ec2.png)

ランタイムURL を変更するには、**設定 > プロパティ** を選択します。ランタイムURL の Prefix を ``/a`` から ``/api`` に変更して、保存ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/bc8606b7-53b6-9d03-7918-f4439b2e244e.png)

Backend URL を変更することで、無事 API Managmement から API を実行することができました。なぜ Prefix が ``/a`` になってしまうのか、原因は不明なのですが、同じリソース (Function App) の再リンクを何度試しても prefix が ``/a`` になってしまう事象が発生しました。もし同じ事象が発生した場合は、Backend の ランタイムURL を確認してみてください。
 
# 参考文献
[Azure API Management の概要](https://docs.microsoft.com/ja-jp/training/modules/introduction-to-azure-api-management/)