FastAPI を Azure Functions Python Programming Model v2 で動かしてみる

# 本記事について

Microsoft Build 2023 で **Azure Functions** の **Python Programming Model v2** が GA (一般提供) となりました。本記事では、この Python Programming Model v2 を利用して、**FastAPI** で作られた Web API を Azure Functions 上にホストする方法を見ていきます。

https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-reference-python?tabs=asgi%2Capplication-level&pivots=python-mode-decorators

# Python Programming Model v2 の特徴

Python Programming Model v2 の特徴は以下になります。

* 単純化されたフォルダー構造。Function App 内のファイルの数が少なくなります。アプリケーション内の複数の関数を同じファイルで定義できるようになりました。

* トリガーとバインディングはデコレーターとして表されるため、function.json という構成ファイルが必要なくなります。

* ブループリント機能のインポートを使った合理化されたワークフロー。ブループリントは、アプリケーション内の機能の論理的なグループ化も促進します。

* VS Code の新しい「テンプレートの表示」オプションを使用すると、ドキュメントに簡単にアクセスできるようになります。

https://techcommunity.microsoft.com/t5/azure-compute-blog/azure-functions-v2-python-programming-model/ba-p/3665168

# VS Code でコードを作成

ここから、VS Code でコードのひな型を作成し、それを変更していきます。

## コマンドパレットから Function App を作成

VS Code でコマンドパレットを開き、Azure Functions: Create Function... を選択します。言語で、Python (Programming Model V2) を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/8bb27da2-a601-f52f-5015-a463debf788e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/ec625996-a0fe-bb34-d0f4-1207b0ad96d8.png)

## FastAPI の Hello World コードを追加

V2 では function.json がなくなったため、Python のファイルにコードを追加するだけでよくなりました。今回のフォルダ構成は下記になります。


```:フォルダ構造
<project_root>/
 | - .venv/
 | - .vscode/
 | - function_app.py
 | - routers
 | | - __init__.py
 | | - hello.py
 | - .funcignore
 | - host.json
 | - local.settings.json
 | - requirements.txt
```

実行する Python コードは下記のファイルを用意しました。

```python:function_app.py
#function_app.py

import azure.functions as func 
from fastapi import FastAPI
from routers import hello

fast_app = FastAPI() 
fast_app.include_router(hello.router)

@fast_app.get("/")
async def root():
    return {"message":"Hello world"}

app = func.AsgiFunctionApp(app=fast_app, http_auth_level=func.AuthLevel.FUNCTION)
```

```python:routers/hello.py
# hello.py

from fastapi import APIRouter

router = APIRouter()

@router.get("/hello/{name}", tags=["hello"])
async def hello_name(name: str):
    return {"message": f"Hello {name}"}

@router.get("/hello", tags=["hello"])
async def hello(name: str = ""):
    return {"message": f"Hello {name}"}
```

```text:requirements.txt
azure-functions
fastapi
```

Azure Functions Python Programming Model v2 における FastAPI の実行ならではのところとしては、下記の部分になります。

```
app = func.AsgiFunctionApp(app=fast_app, http_auth_level=func.AuthLevel.FUNCTION)
```

また、`host.json` のファイルは下記のようにします。

```json:host.json
{
  "version": "2.0",
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    }
  },
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[4.*, 5.0.0)"
  },
  "extensions": {
    "http": {
      "routePrefix": ""
    }
  }
}
```

Fast API や Flask を Azure Functions の HTTP トリガーを使う関数としてホストする場合、`http` の `routePrefix` が Extension の設定が必要になります。

公式ドキュメントとしては下記をご参照ください。

https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-reference-python?tabs=asgi%2Capplication-level&pivots=python-mode-decorators#web-frameworks

# Azure Functions にデプロイ

Azure Portal で関数アプリを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/89dc659f-0305-e94f-1617-1ee1a3fc4bc8.png)

そして、VS Code からデプロイしてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/3fdd4ce0-6b6e-67a1-1c25-59b32fe54ef8.png)

関数アプリにアクセスすると下記のように表示されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/0a8ae7f7-d368-b0f5-c8a4-87706037fbb7.png)

# (補足) Application Insights について

Azure Functions では、組み込みで Azure の APM である、**Application Insights** を有効化することができます。ただし、FastAPI をホストする場合、トレーシングを行うには**手動でコードに数行インストルメンターを組み込む**必要があります。

* Python の利用モジュール

```txt:requirements.txt
opentelemetry-instrumentation-fastapi
azure-monitor-opentelemetry
```

* Python コード

```python:function_app.py
from azure.monitor.opentelemetry import configure_azure_monitor
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor

configure_azure_monitor(
    connection_string="<Application Insights の接続文字列>",
)
FastAPIInstrumentor.instrument_app(fast_app)
```

これにより下記のようにトレーシングを行えます。(下記のスクリーンショットは、上記の `hello.py` を修正し、リクエスト内容を Cosmos DB に記録するようにした関数のものです。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/20b7ba69-8911-b820-9ce0-41958508e2c7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/853186da-a7c8-73be-dc95-5f831261d90e.png)

Application Insights による Python アプリについては、下記もご参照ください。

https://qiita.com/YoshiakiOi/items/c4de9b1ffc01ecf292f9

# 最後に

＊本稿は、個人の見解に基づいた内容であり、所属する会社の公式見解ではありません。また、いかなる保証を与えるものでもありません。正式な情報は、各製品の販売元にご確認ください。