Azure API Management - SwaggerからのAPIインポート、Functionsとの連携

# 目的

Azure API Managementの基本操作と、BackendにFunctionsを連携する方法を確認する

# API Management インスタンスの作成

公式ドキュメント（[Azure portal を使用して新しい Azure API Management サービス インスタンスを作成する](https://docs.microsoft.com/ja-jp/azure/api-management/get-started-create-service-instance)）
を参照
※API Management サービス インスタンスがオンラインになるまで20~30分程度かかる

# API作成

## Swaggerの用意

以下の適当なSwaggerファイルを用意

```yaml:swagger.yaml
openapi: 3.0.1
info:
  description: 'REST API 定義'
  version: '1.0.0'
  title: restApi
paths:
  /:
    get:
      responses:
        200:
          description: 'OK'
        400:
          description: 'Bad Request'
  /api:
    get:
      responses:
        200:
          description: 'OK'
        400:
          description: 'Bad Request'
```

## SwaggerからAPI のインポート

1．Azure portalで、`API` → `+Add API` → `OpenAPI`を選択
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/7810af0e-54e9-e7c0-421f-1ff62640b99b.png)

2．`Select a file`から用意したSwaggerファイルを選択
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/442d0ffa-28b8-87db-6e05-520b1849ab03.png)

3．以下インポートが完了した状態
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/bb28c759-884f-79fe-1a86-a721b4ef20a3.png)

## 製品にAPIの追加

※今回はデフォルトで用意されている`Starter`を使用する

1．Azure portalで、`製品` → `Starter`を選択
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/2330416d-e9e0-9c1e-e46e-c124282b9087.png)

2．`+APIの追加` → 作成したAPIにチェックを入れ`選択`をクリック
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/557bc40b-31f0-54ca-b6ab-b7f0698cff7f.png)

# Backend設定

## httpbinを使用する

HTTPリクエストに対して簡単な応答を返してくれるサービス`httpbin`をBackendに設定する
`https://httpbin.org/get`に対してリクエストを送信すると、送信したパラメータやヘッダー情報がレスポンスされる

1．Azure portalで、`Design` → `/`のAPIを選択
2．Backendの編集ボタンを選択
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/e99b5ab4-7c5a-9fa2-b3bb-3b60a777b6c7.png)

3．`Override`にチェックを入れ、`Service URL`に`https://httpbin.org/get`を入力
4．`Save`をクリック
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/8c971b45-9d53-3771-0cf0-65bfbfcd25da.png)

## Functionsを使用する

### 関数作成

トリガーがHTTPの関数を作成する
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/30af3667-869f-a840-a8b1-09e12f09b47d.png)

関数はデフォルトのまま使用

```python
import logging

import azure.functions as func


def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    name = req.params.get('name')
    if not name:
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            name = req_body.get('name')

    if name:
        return func.HttpResponse(f"Hello, {name}. This HTTP triggered function executed successfully.")
    else:
        return func.HttpResponse(
             "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.",
             status_code=200
        )
```

### FunctionsからAPIをインポートする

1．Azure portalで、作成したAPIの右にある設定 → `import`を選択
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/6d100f21-8071-128b-445c-fb32b048025e.png)

2．Function Appを選択
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/43826362-fb0d-5c34-556c-fc076970c068.png)

3．`*関数アプリ` → 作成した関数アプリを選択し`選択`をクリック
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/be625943-6bd8-78d9-a911-615bae5b4294.png)

3．`選択`をクリック
![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/2935604b-2f3f-8025-6af4-fe2b346642fb.png)

4．以下インポート結果
![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/5effc55c-d04a-b259-8c19-c0c098484f0d.png)

### ルーティング設定

[Azure Functions の HTTP トリガー](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-http-webhook-trigger?tabs=csharp#configuration)

`function.json` の `route` を追記することでURLを設定できる

```json:function.json
{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "get"
      ],
      "route": "data1/{id:int}"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
  ]
}
```

以下の`route`設定を行った場合、

HttpTrigger1：route記載なし
HttpTrigger2："data1/{id:int}"
HttpTrigger3："{group}/{id:int}"

API Management にインポートすると以下のようにURLが設定される

![image-20210717115009673.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/ecc2745e-e3c8-0e20-dbd5-144ba269cf96.png)
![image-20210717115040300.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/75d01238-5cfa-c1dc-5e9f-e42cb4d44ae1.png)
![image-20210717115102088.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/be63ad02-9eb8-c5b3-e13c-758e236d82ba.png)


# テスト&トラブルシューティング

1．Azure portalで、`Test` → `/`のAPIを選択 → `Send`をクリック
![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/d0e01ce5-27f1-598c-1adf-5d8801633532.png)

2．`200 OK`が返ってくることを確認
※外部からAPIをコールする場合はヘッダに`Ocp-Apim-Subscription-Key`を指定する必要がある
![15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/e8cdf53d-7863-fcda-59af-e538f3d8b0de.png)

BackendがFunctionsの`HttpTrigger1`のAPIでも同様、関数でレスポンスしている文字列が取得できている
![16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/8f283de1-001b-a18f-3dff-4d30c1dcb102.png)

## APIのレスポンスが空になる

![17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/c1f6a79e-5dcb-0b16-4bab-5aaa99016473.png)
`Test`を行うとレスポンスが`200 OK`だが、レスポンスのbodyが空（content-length: 0）となる現象が発生した
※一度APIを削除後、再度Swaggerからインポートし直したところ発生しなくなった

症状と解決法について公式ドキュメント（[AzureAPIが空白の応答を返しています](https://docs.microsoft.com/en-us/troubleshoot/azure/general/api-return-blank-response)）に記載があった

### 解決方法（転送要求ポリシーを設定する）

[転送要求ポリシー](https://docs.microsoft.com/en-us/azure/api-management/api-management-advanced-policies#ForwardRequest)が設定されていない場合、リクエストはBackendサービスに送信されず、即正常完了を応答する
以下のようにポリシーに`forward-request`を追加する

```yaml
<!-- api level -->
<policies>
    <inbound>
        <base/>
    </inbound>
    <backend>
        <forward-request timeout="60"/>
    </backend>
    <outbound>
        <base/>
    </outbound>
</policies>
```

ポリシーは以下の`</>`から編集する
![18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/1c163f9f-d8dd-79c9-8522-bf4a221976e0.png)