Open11

Azure Blob

sayasaya

Azure Blob Storage と Python で作業を開始する

https://learn.microsoft.com/ja-jp/azure/storage/blobs/storage-blob-python-get-started?tabs=azure-ad

マネージドIDでBlob Storage へのアクセスを承認

https://learn.microsoft.com/ja-jp/azure/developer/python/sdk/authentication-azure-hosted-apps?toc=%2Fazure%2Fstorage%2Fblobs%2Ftoc.json&bc=%2Fazure%2Fstorage%2Fblobs%2Fbreadcrumb%2Ftoc.json&tabs=azure-portal%2Cazure-app-service

Blob Storage へのアクセスを承認して接続する最も簡単で安全な方法

DefaultAzureCredential を使用してアクセスを承認

https://learn.microsoft.com/ja-jp/azure/storage/blobs/storage-blob-python-get-started?tabs=azure-ad#authorize-access-using-defaultazurecredential

def get_blob_service_client_token_credential(self):
    # TODO: Replace <storage-account-name> with your actual storage account name
    account_url = "https://<storage-account-name>.blob.core.windows.net"
    credential = DefaultAzureCredential()

    # Create the BlobServiceClient object
    blob_service_client = BlobServiceClient(account_url, credential=credential)

    return blob_service_client
  • account_urlは、Azure BlobストレージのアカウントにアクセスするためのURLを指定。
  • DefaultAzureCredentialは、Azure SDK for Pythonが提供する資格情報クラス。
  • BlobServiceClientは、Azure Blobストレージを操作するための主要なクラス。これにより、Blobコンテナの作成、一覧表示、削除などの操作ができる。このオブジェクトを作成する際に、上で設定したaccount_urlとcredentialを引数として渡している。

この関数を使うことで、Azure Blobストレージに簡単に接続できるようになる。

sayasaya

Python 用 Azure Storage クライアント ライブラリを使用してデータ リソースを操作し、特定のアクションを実行する方法

https://learn.microsoft.com/ja-jp/azure/storage/blobs/storage-blob-python-get-started?tabs=azure-ad#build-your-application

Python を使用してブロック BLOB をアップロード

https://learn.microsoft.com/ja-jp/azure/storage/blobs/storage-blob-upload-python

upload_blob

このメソッドは、自動チャンクを使用してデータ ソースから新しい BLOB を作成。

Azure Blob Storageに格納されているファイルを別の形式や構造に整理してダウンロードしたい場合、そのファイルを必ずしもローカルにダウンロードする必要はない!

Azure Functions: Azure Functionsを使用して、Blob Storageに新しいファイルが追加されたときなどのトリガーで自動的に関数を実行することができる。この関数内で、BLOBの内容を読み取り、必要に応じて変換・整理し、結果を別のBLOBとして保存することができる。

  1. Azure Functionsのプロジェクトをセットアップする
    まず、Azure Functionsのプロジェクトをセットアップします。これには、Azure Functions ToolsやAzure CLIなどのツールが必要です。

  2. Blob Storageトリガーの設定
    Blob Storageトリガーを使って、特定のコンテナにファイルが追加または更新されたときに関数を自動的に実行するように設定します。

import azure.functions as func

def main(myblob: func.InputStream, outputblob: func.Out[func.InputStream]):
    # myblob にはトリガーされたBlobのデータが含まれています

    # データの読み取り
    data = myblob.read()

    # データの整理・変換処理(簡単な例として文字列を大文字に変換)
    transformed_data = data.upper()

    # 変換後のデータを別のBlobに保存
    outputblob.set(transformed_data)
  1. function.json の設定
    関数の設定ファイル function.json で、Blobのトリガーとアウトプットバインディングを設定します。
Copy code
{
  "bindings": [
    {
      "name": "myblob",
      "type": "blobTrigger",
      "direction": "in",
      "path": "input-container/{name}",
      "connection": "AzureWebJobsStorage"
    },
    {
      "name": "outputblob",
      "type": "blob",
      "direction": "out",
      "path": "output-container/{name}",
      "connection": "AzureWebJobsStorage"
    }
  ]
}

この設定では、input-container に新しいファイルが追加されると関数がトリガーされ、処理後のファイルは output-container に保存されます。

  1. 必要なパッケージのインストール
    Azure FunctionsでBlob Storageを操作するためには、適切なパッケージが必要です。これは、通常、requirements.txtにリストアップして、pip install -r requirements.txtでインストールします。

例:

azure-functions
azure-storage-blob
  1. デプロイと実行
    Azure FunctionsのプロジェクトをAzureにデプロイします。デプロイ後、input-containerにファイルをアップロードすると、上記の関数が自動的にトリガーされ、データの変換が行われた後にoutput-containerに結果が保存されます。
sayasaya

Durable Functions

クライアント関数: API Managementから呼び出されるクライアント関数をセットアップします。この関数はオーケストレーター関数を起動する役割を持ちます。

import azure.functions as func
import azure.durable_functions as df

def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
    client = df.DurableOrchestrationClient(starter)
    instance_id = client.start_new(req.route_params['functionName'], None, None)
    return client.create_check_status_response(req, instance_id)

オーケストレーター関数: この関数はアクティビティ関数の実行順序を定義します。

def orchestrator_function(context: df.DurableOrchestrationContext):
    try:
        # 1つ目のアクティビティ関数を呼び出す
        result1 = yield context.call_activity('ActivityFunction1', None)

        # 2つ目のアクティビティ関数を呼び出す
        result2 = yield context.call_activity('ActivityFunction2', result1)

        # 3つ目のアクティビティ関数を呼び出す
        result3 = yield context.call_activity('ActivityFunction3', result2)

        # 最終的な結果を返す
        return {"status": "success", "message": result3}
    except Exception as e:
        return {"status": "error", "message": str(e)}

アクティビティ関数: Blobからファイルを読み取り、条件に基づいてデータを整理し、結果をBlobにアップロードします。ここではダウンロードとアップロードの操作を行いますが、ダウンロードしたデータは関数のメモリ内で処理され、ローカルに保存されません。

import azure.functions as func
from azure.storage.blob import BlobClient

def main(name: str) -> str:
    # Blobからデータを読み取る
    blob_client = BlobClient.from_connection_string("YOUR_CONNECTION_STRING", "your_container_name", "your_blob_name")
    blob_data = blob_client.download_blob().readall()

    # ファイル名やデータの条件判定と整理を行う
    # ...

    # 整理したデータをBlobにアップロード
    output_blob_client = BlobClient.from_connection_string("YOUR_CONNECTION_STRING", "output_container_name", "output_blob_name")
    output_blob_client.upload_blob(blob_data)

    return "Success"

(関数内でBlobからダウンロードしたデータを変数blob_dataに保存しています。したがって、blob_data変数を通じてダウンロードしたデータにアクセスできます。)


host.json と function.json の設定: Durable Functionsを使用する場合、
これらの設定ファイルに適切なバインディングと設定を追加する必要があります。

また、セキュリティの観点から、機密情報(例: 接続文字列)を環境変数やAzure Key Vaultに保存した方がいい。

設定ファイルに適切なバインディングと設定とは?

Azure FunctionsとDurable Functionsを使用する場合、関数のトリガーや入出力のバインディング、および関数の動作に関する設定は主にhost.jsonとfunction.jsonの2つの設定ファイルで行われます。

host.json:

全体のAzure Functionsアプリに適用される設定を含む。
Durable Functionsの場合、タスクハブ、永続的なストレージ、タイムアウトなどのDurableタスク関連の設定も行う。
Durable Functions用の基本的なhost.jsonの設定例:

{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "hubName": "MyTaskHub",
      "storageProvider": {
        "connectionStringName": "AzureWebJobsStorage"
      }
    }
  }

function.json:

各関数ごとに関連する設定を持つ。
トリガーの種類、バインディングの情報、関数が使用するリソースへの接続情報などを定義する。
Durable Functionsのクライアント関数のfunction.jsonの設定例:

{
  "bindings": [
    {
      "name": "req",
      "type": "httpTrigger",
      "direction": "in",
      "methods": ["get", "post"]
    },
    {
      "name": "$return",
      "type": "http",
      "direction": "out"
    },
    {
      "name": "starter",
      "type": "orchestrationClient",
      "direction": "in"
    }
  ]
}

オーケストレーター関数のfunction.jsonの設定例:

{
  "bindings": [
    {
      "name": "context",
      "type": "orchestrationTrigger",
      "direction": "in"
    }
  ]
}

アクティビティ関数のfunction.jsonの設定例:

{
  "bindings": [
    {
      "name": "name",
      "type": "activityTrigger",
      "direction": "in"
    }
  ]
}

これらの設定ファイルを適切に構成することで、Azure FunctionsとDurable Functionsの動作をカスタマイズできます。

バインディングとは

バインディング(Binding)は、Azure Functionsの主要な概念の一つで、関数がデータにアクセスする方法を単純化するための宣言的な方法を提供します。

バインディングを使用すると、関数のコードがストレージアカウント、データベース、メッセージキューなどの外部リソースと直接的に通信することなく、これらのリソースからデータを読み取ったり、データを書き込んだりすることができます。

バインディングには主に3つのタイプがあります!

  1. トリガーバインディング (Trigger Bindings):

関数の実行を開始するイベントをリッスンするバインディング。
例: HTTPリクエスト、Blob Storageの新しいBlobの作成、Queue Storageの新しいメッセージなど。

  1. 入力バインディング (Input Bindings):

関数が実行されるときにデータを取得するためのバインディング。
例: Cosmos DBからのドキュメントの読み取り、Blob StorageからのBlobの読み取りなど。

  1. 出力バインディング (Output Bindings):

関数の実行結果を外部リソースに書き込むためのバインディング。
例: Cosmos DBへのドキュメントの書き込み、Queue Storageへのメッセージの追加、Blob StorageへのBlobの書き込みなど。

例:
以下は、Azure Functionsの関数でBlob Storageのトリガーバインディングと出力バインディングを使用する例です。

関数のコード:

def main(myblob: func.InputStream, outputblob: func.Out[func.InputStream]):
    data = myblob.read()
    # データの処理...
    outputblob.set(processed_data)

function.jsonのバインディング設定:

{
  "bindings": [
    {
      "name": "myblob",
      "type": "blobTrigger",
      "direction": "in",
      "path": "input-container/{name}",
      "connection": "AzureWebJobsStorage"
    },
    {
      "name": "outputblob",
      "type": "blob",
      "direction": "out",
      "path": "output-container/{name}",
      "connection": "AzureWebJobsStorage"
    }
  ]
}

この例では、input-containerに新しいBlobが追加されると、関数がトリガーされます。関数のコード内でデータの処理が行われ、処理されたデータはoutput-containerに新しいBlobとして書き込まれます。

要点として、バインディングを使用することで、関数のコードは外部リソースの詳細(接続文字列、認証、APIの詳細など)を知らなくても、データの読み取りや書き込みが可能になります。

接続文字列

接続文字列は、アプリケーションやサービスが別のサービスやデータベースに接続するために必要な情報を含む文字列です。接続文字列は、接続先の情報、認証情報、特定の接続属性や設定など、接続に必要な詳細を提供します。

一般的に、接続文字列は以下のような情報を含みます!

  1. エンドポイント: 通常、ホスト名やURL形式で、接続先のサービスやデータベースの場所を示します。

  2. 認証情報: ユーザー名やパスワード、APIキー、SASトークン(Azure Blob Storageの場合)など、接続先にアクセスするための資格情報。

  3. その他の接続属性: タイムアウト設定、プロトコルのバージョン、暗号化のオプションなど、接続の動作をカスタマイズするための追加の属性や設定。

例として、Azure SQL Databaseの接続文字列は以下のような形式を取ることがよくあります。

Server=tcp:myserver.database.windows.net,1433;Initial Catalog=mydatabase;Persist Security Info=False;User ID=mylogin;Password=mypassword;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;

この接続文字列は以下の情報を提供しています。

  • Server: 接続先のSQL Serverのホスト名とポート。
  • Initial Catalog: 接続したいデータベースの名前。
  • User IDとPassword: 認証のためのユーザー名とパスワード。
  • Encrypt: 通信を暗号化するかどうかの設定。
  • TrustServerCertificateやConnection Timeoutなどのその他の設定。

接続文字列は機密情報として扱うべきであり、第三者に漏洩することなく、安全に管理する必要があります。不正にアクセスされた場合、攻撃者は接続文字列を利用して、データベースやサービスにアクセスできるリスクがあります。

sayasaya

blobのファイル名を取得したい

すでにblobにデータがアップロードされたときにAPI ManagementでAzure Functionを呼び出している。Blob トリガーを使用してファイル名を取得するのは冗長では?

(Blob トリガーは、Blob Storageに新しいデータが追加されたときに自動的にAzure Functionを起動するためのもの。すでにAPI Managementを使って関数がトリガーされている場合、同じイベントを2回処理することになる可能性がある。)

ファイル名を取得する他の方法

  1. API呼び出し時にファイル名を渡す:API ManagementからAzure Functionを呼び出すときに、ファイル名やBlobのURLをパラメータとして渡す方法です。この方法では、Azure FunctionはAPIから直接ファイル名を取得することができ、Blobから該当のデータを読み取る際にそのファイル名を使用できます。

  2. Azure Storage SDKを使用する:Azure Storage SDKを使用して、特定のBlob Container内のBlobのリストを取得し、それを基に処理を行う方法です。ただし、この方法は特定のBlobをターゲットにする場合には効率的ではないかもしれません。

  3. メタデータの利用:Blobをアップロードする際に、関連するメタデータ(例:ファイル名)をBlobに付与することができます。このメタデータは後で読み取ることができるため、API Managementから関数を呼び出す際に特定のBlobのメタデータを基に処理を行うことができます。

おそらく、最もシンプルで効率的な方法は、API ManagementからAzure Functionを呼び出す際にファイル名をパラメータとして渡す方法では??

API Managementを通じてDurable Functionsを起動する場合、Blobにアップロードされたファイル名の命名則をチェックする処理を組み込む方法

  1. APIからファイル名を取得

既にAPI Managementを使用してAzure Functionを起動している場合、APIリクエスト時にファイル名をパラメータとしてAzure Functionに渡すように設定します。

例えば、API Managementを通じて次のようなURLを使用してAzure Functionを呼び出すことができるとします。

https://your-azure-function-url/api/your-function-name?blob_filename=sample-blob.txt

このURLはsample-blob.txtというファイル名をblob_filenameとしてAzure Functionに渡します。Azure Functionはこのファイル名を使用してBlob Storageの該当のデータを処理します。

  1. クライアント関数の実装

この関数はAPI Managementからのリクエストを受け取り、オーケストレーター関数を起動します。
ファイル名をオーケストレーター関数に渡します。

def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
    client = df.DurableOrchestrationClient(starter)
 # Durable Functions の操作を行うためのクライアントを初期化

 # APIからファイル名を取得
    blob_filename = req.params.get('blob_filename')
    if not blob_filename:
        return func.HttpResponse("blob_filename parameter is required", status_code=400)

    instance_id = client.start_new("orchestrator_function", None, blob_filename)
  # client.start_new() はオーケストレーター関数を開始するためのメソッド
  # req.route_params['functionName'] で指定されたオーケストレーター関数を開始
    
    return client.create_check_status_response(req, instance_id)

このメソッドは、オーケストレーションの新しいインスタンスを開始し、そのインスタンスのIDを返す。この方法で、クライアント関数はオーケストレーター関数を開始し、そのオーケストレーションの進行状況をチェックするためのHTTPレスポンスを返すことができる!

  1. オーケストレーター関数の実装

オーケストレーター関数は、ファイル名の命名則をチェックするアクティビティ関数を呼び出します。

def orchestrator_function(context: df.DurableOrchestrationContext):
    blob_filename = context.get_input()
    
    # 命名則をチェックするアクティビティ関数を呼び出す
    is_valid = yield context.call_activity('CheckNamingConvention', blob_filename)
    # CheckNamingConvention という名前のアクティビティ関数を呼び出し、その関数に blob_filename を引数として渡す。

    if is_valid:
        # その他の処理やアクティビティ関数を呼び出す...
        pass

    return is_valid

yield:

  • yield は Python のジェネレータの構文です。ジェネレータはイテレータとして機能する関数で、通常の関数とは異なり、ジェネレータは実行を一時停止して後で再開できます。
  • Durable Functions のコンテキストでは、yield はオーケストレーター関数内で非同期のアクティビティ関数を呼び出すために使用されます。アクティビティ関数が完了すると、その結果が yield の右側の式から返され、左側の変数に代入されます。

context.call_activity:

  • context.call_activity は、指定したアクティビティ関数を非同期に呼び出すメソッドです。
  • このメソッドはオーケストレーター関数内で使用され、第一引数としてアクティビティ関数の名前を取り、第二引数以降にはアクティビティ関数に渡すパラメータを取ります。
  1. アクティビティ関数の実装

アクティビティ関数は、渡されたファイル名の命名則をチェックします。
命名則が正しいかどうかに応じて、次のアクションを決定します(例:ファイルをBlobから読み取る、別のアクティビティ関数を呼び出す、エラーメッセージを返すなど)。

def check_naming_convention(blob_filename: str) -> bool:
# blob_filename という名前の文字列型の引数を受け取り、bool 型の戻り値を返すことを期待している。
    # ファイル名の命名則をチェックするロジック...
    if "特定の条件":
        return True
    else:
        return False
sayasaya

サンプルコード

import re # 正規表現
import datetime
import csv # CSVの読み書きをサポート
from io import StringIO # StringIOクラスは、文字列データをファイルのように扱うことができるクラス
from azure.storage.blob import BlobClient

def process_blob_data(blob_filename: str) -> dict:
    # 1の命名則の確認
    match = re.match(r"^[a-zA-Z]{3}_(\d{3})", blob_filename)
    if not match:
        return {"status": "invalid_name"}

    # 3桁の半角英数字を取得
    three_chars = match.group(1)

    # BlobからCSVデータを読み込む
    blob_client = BlobClient.from_connection_string("YOUR_CONNECTION_STRING", "your_container_name", blob_filename)
    blob_data = blob_client.download_blob().readall().decode("utf-8")

    csv_reader = csv.reader(StringIO(blob_data))
    data_rows = list(csv_reader)

    # A列の1行目のデータがXのフォーマットか判定
    if not re.match(r"^X_PATTERN$", data_rows[0][0]):  # X_PATTERNは実際のパターンに置き換えてください
        return {"status": "invalid_format"}

    a1_data = data_rows[0][0]

    # A列とC列のデータを取得およびクレンジング
    col_a_data = []
    col_c_data = []
    for row in data_rows:
        # ここで、型の異なるデータ、桁数が超えているデータ、NotNullの空白文字などのチェックとクレンジングを行う

        col_a_data.append(row[0])
        col_c_data.append(row[2])

    # ファイルを出力
    today = datetime.datetime.today().strftime('%Y%m%d')
    invalid_data_filename = f"efb/{today}/invalid_data.txt"
    normal_data_filename = f"efb/{today}/normal_data.txt"

    # invalid_dataとnormal_dataをblobにアップロード
    # この部分は具体的なファイル内容の作成と保存に関するロジックに基づいて調整が必要です。

    return {"status": "success", "invalid_data_filename": invalid_data_filename, "efb_data_filename": normal_data_filename}

サンプルコード2

import csv
from io import StringIO
from datetime import datetime
from azure.storage.blob import BlobClient

def cleanse_and_upload(blob_filename: str, csv_content: str) -> None:
    # CSVを解析
    reader = csv.DictReader(StringIO(csv_content))
    rows = list(reader)
    
    # クレンジング処理
    invalid_data = []
    normal_data = []

    for row in rows:
        # A列とC列を取得
        a_value = row.get('A', '').strip()
        c_value = row.get('C', '').strip()
        
        # NotNullの空白文字のチェック
        if not a_value or not c_value:
            invalid_data.append(row)
            continue
        
        # ここでその他の型チェックや桁数チェックなどを行う
        # 例: A列のデータが最大5文字であることを期待
        if len(a_value) > 5:
            invalid_data.append(row)
            continue
        
        # 有効なデータをefb_dataに追加
        normal_data.append(row)

    # データをBlobにアップロード
    today = datetime.today().strftime('%Y%m%d')
    blob_client_invalid = BlobClient.from_connection_string("YOUR_CONNECTION_STRING", "your_container_name", f"efb/{today}/invalid_data.txt")
    blob_client_efb = BlobClient.from_connection_string("YOUR_CONNECTION_STRING", "your_container_name", f"efb/{today}/efb_data.txt")

    # クレンジングされたデータをBlobにアップロード
    blob_client_invalid.upload_blob("\n".join([",".join(row.values()) for row in invalid_data]))
    blob_client_normal.upload_blob("\n".join([",".join(row.values()) for row in normal_data]))

サンプルコード3

一つ目のアクティビティ関数
from azure.storage.blob import BlobClient
import csv
from io import BytesIO

def first_activity_function(context: df.DurableActivityContext) -> dict:
    connection_string = 'YOUR_CONNECTION_STRING'
    container_name = 'YOUR_CONTAINER_NAME'
    blob_filename = 'YOUR_BLOB_FILENAME'

    blob_client = BlobClient.from_connection_string(connection_string, container_name, blob_filename)

    # Blobからデータをダウンロード
    stream = BytesIO(blob_client.download_blob().readall())
    
    # CSVを読み込む
    csv_reader = csv.reader(stream.decode('utf-8').splitlines())
    column_A = []
    column_C = []

    for row in csv_reader:
        column_A.append(row[0])  # A列
        column_C.append(row[2])  # C列

    # ファイル名の一部を取得
    part_of_filename = blob_filename.split('_')[1]  # 例えば、'prefix_123_suffix.csv'から'123'を取得

    # データを辞書としてまとめる
    data = {
        'filename_part': part_of_filename,
        'column_A': column_A,
        'column_C': column_C
    }

    return data
オーケストレーター関数
def orchestrator_function(context: df.DurableOrchestrationContext):

    # 1つ目のアクティビティ関数を呼び出す
    data_from_first_activity = yield context.call_activity('FirstActivityFunction', None)

    # 2つ目のアクティビティ関数を呼び出し、取得したデータを引数として渡す
    result_from_second_activity = yield context.call_activity('SecondActivityFunction', data_from_first_activity)

    return result_from_second_activity
二つ目のアクティビティ関数
def second_activity_function(context: df.DurableActivityContext, input_data: dict):
    part_of_filename = input_data['filename_part']
    column_A = input_data['column_A']
    column_C = input_data['column_C']

    # ここでデータを処理...

    return # 何らかの結果

input_data は、オーケストレーター関数から渡された data_from_first_activity の内容を受け取るものです。

sayasaya

Azure API Management (APIM) を使用して Azure Functions を呼び出す方法

1. Azure Function のセットアップ

  • Azure Functions の作成
  • 関数を作成(HTTPトリガーを使用)
  • Azure Portalから関数のURLを取得、これは後で API Management で使用

2. Azure API Management のセットアップ

  • Azure Portal で新しいAPI Management インスタンスの作成
  • 「API」セクションに移動して、新しいAPIを作成
  • バックエンドの設定で、Function App の URL を指定
  • 必要に応じて、リクエスト/レスポンスのポリシーを設定(リクエストやレスポンスを変更するためのルールを追加することができる)

3. アップロード画面の設定

  • アップロード画面から API Management のエンドポイントを呼び出すロジックの実装
  1. ユーザーがファイルをアップロード画面にドラッグ&ドロップまたは選択することで、ファイルがクライアントサイドに読み込まれます。
  2. アップロードボタンをクリックすると、API Management のエンドポイントに向けてHTTPリクエスト(通常は POST リクエスト)が送信されます。
  3. API Management はリクエストを受け取り、設定したポリシーに基づいてリクエストを処理し、バックエンドの Azure Function に転送します。
  4. Azure Function は処理を実行し、結果を API Management に返します。
  5. API Management はクライアントに結果を返します。
  6. クライアントサイドのロジックで結果を処理し、ユーザーにフィードバックを提供します。

Azure API Management (APIM) の主な役割

一つ以上のバックエンドサービス(この場合はAzure Functions)の前にAPIゲートウェイを設置し、リクエストとレスポンスのルーティング、変換、検証などの操作を中央で制御すること。

APIMを使ってAzure Functionsを呼び出す際の基本的なフロー

  1. APIの公開: APIM内でAPIを定義し、バックエンドサービスとしてAzure FunctionsのURLを指定します。

  2. エンドポイントの設定: APIMは、公開されたAPIにアクセスするための新しいエンドポイントURLを提供します。このURLは、クライアント(例: Webアプリ、モバイルアプリなど)が利用します。

  3. リクエストのルーティング: クライアントからのリクエストは、最初にAPIMに到達します。APIMはそのリクエストを適切なバックエンドサービス(Azure Functions)にルーティングします。

  4. レスポンスの返送: Azure Functionsからのレスポンスは、APIMを通じてクライアントに返されます。この際、APIMでレスポンスの内容を変更することも可能です。

  5. セキュリティとポリシーの適用: APIMでは、リクエストやレスポンスに対するポリシーや、認証・認可、レートリミット、キャッシングなどの機能を簡単に適用することができます。

要するに、クライアントはAPIMのエンドポイントURLにリクエストを送るだけで、APIMが背後でAzure Functionsなどの実際のバックエンドサービスを呼び出して処理を行い、その結果をクライアントに返すという流れになる!!


APIを定義

  • API(Application Programming Interface)とは、ソフトウェアの機能やデータを外部のプログラムやサービスから利用できるようにするための仕様やインターフェースです。
  • 「APIを定義する」とは、APIが提供する機能、リクエストの形式、レスポンスの形式、エンドポイントのURLなど、APIの詳細な仕様を設定することを意味します。
  • Azure API Management (APIM) においては、APIを定義することで、どのようなリクエストを受け付け、どのバックエンドサービス(例: Azure Functions)にルーティングするかなどの設定を行います。

エンドポイントURL:

  • エンドポイントとは、APIやサービスにアクセスするためのURLやURIを指します。
  • たとえば、Webサイトにアクセスするとき、ブラウザのアドレスバーにURL(例: https://www.example.com/)を入力しますが、このURLはWebサイトのエンドポイントとなります。
  • APIにおいても、そのAPIの機能を利用するためには特定のエンドポイントURLにリクエストを送る必要があります。
  • APIMにおいては、公開されるAPIごとに独自のエンドポイントURLが提供されます。クライアントはこのエンドポイントURLを通じてAPIにアクセスし、必要な処理を実行します。
  • APIMを使用する場合、エンドポイントURLは通常APIMのドメイン名を含むURLとなります。

例えば、天気情報を提供するAPIがあるとします。そのAPIのエンドポイントURLが https://api.weather.com/v1/current だとした場合、このURLにリクエストを送ることで現在の天気情報を取得できる、というのがAPIの仕組みです。APIMを使用している場合、実際のバックエンドサービス(天気情報を提供するサーバ)の前にAPIMが配置され、クライアントはAPIMのエンドポイントURLを通じてリクエストを行い、APIMがバックエンドサービスにリクエストを中継して処理を行います。

APIリクエスト

  • APIリクエストは、APIのエンドポイントURLに対して行われるHTTPリクエストのことを指します。このリクエストを通じて、APIが提供する機能を利用することができます。例えば、データの取得、更新、削除などの操作をAPI経由で実行する場合、対応するAPIのエンドポイントにリクエストを送ります。
APIリクエストの具体例

HTTPリクエストを使用してRESTful APIを呼び出すシナリオを想定。

GETリクエスト
URLからデータを取得する基本的なリクエスト。通常、リソースの取得や情報の問い合わせに使用されます。

GET https://api.example.com/users/123

POSTリクエスト
新しいリソースを作成するためのリクエスト。通常、新しいデータの追加やフォームの送信に使用されます。

POST https://api.example.com/users

{
  "name": "John Doe",
  "email": "john.doe@example.com"
}

PUTリクエスト
既存のリソースを更新するためのリクエスト。全体のリソースを更新します。

PUT https://api.example.com/users/123

{
  "name": "John A. Doe",
  "email": "john.adam.doe@example.com"
}

このリクエストは、IDが123のユーザーの情報を更新するためのものです。

PATCHリクエスト

PATCH https://api.example.com/users/123

{
  "email": "new.email@example.com"
}

DELETEリクエスト

DELETE https://api.example.com/users/123

このリクエストは、IDが123のユーザーを削除するためのものです。

URLの例

(https://your-azure-function-url/api/your-function-name?blob_filename=sample-blob.txt)
このURLは、Azure Functionを呼び出すためのサンプルURLです。

このURLの構造は以下のようになっています。

  • https://your-azure-function-url/: Azure FunctionのベースURL。
  • api/: APIのプレフィックス。
  • your-function-name: 呼び出したいAzure Functionの名前。
  • blob_filename=sample-blob.txt: クエリパラメータ。この例では、blob_filenameという名前のパラメータにsample-blob.txtという値を設定しています。

もし、このURLがAPIMを通じて公開されている場合、エンドポイントURLはAPIMのドメイン名を含むURLとなります。そして、そのURLを使用してAzure Functionを呼び出すことができます。

エンドポイントとURLの違い

  • 一般的に、エンドポイントはサービスにアクセスするためのURLを指します。したがって、上記のURL例も一つのエンドポイントと考えることができます。
  • しかし、エンドポイントは広い意味合いを持ち、URLだけでなくIPアドレスやポート番号も含めた接続先全体を指すこともあります。
sayasaya

ファイル名の取得について

URLにファイル名を含める場合、一般的にはクエリパラメータやURLのパスの一部として含める方法が考えられます。この設定はAPI Management (APIM) 内で行います。そして、そのファイル名はリクエストを行うクライアント(例えばPower Appsや他のアプリケーション)が指定するものです。

クエリパラメータとしてファイル名を指定する方法の例
  1. APIMでのAPI定義

APIM内で新しいAPIを作成または編集します。
このAPIのエンドポイントURLを定義します。例: https://your-apim-service-name.azure-api.net/myapi
バックエンドの設定で、Azure FunctionsのURLを指定します。
クエリパラメータとしてfilenameを受け取るように設定します。

  1. クライアントからのリクエスト

アプリケーションやPower AppsなどのクライアントからAPIを呼び出すときに、ファイル名をクエリパラメータとしてURLに含めてリクエストします。
例: https://your-apim-service-name.azure-api.net/myapi?filename=myfile.txt

  1. Azure Functionsの処理

Azure Functions側でリクエストを受け取る際、クエリパラメータからfilenameを取得します。
このファイル名をもとに、Blob Storageから対象のファイルを処理します。
この方法で、リクエスト時に毎回異なるファイル名をURLに含めてAzure Functionsに渡すことができます。リクエストを行うクライアント側が適切なファイル名を指定する必要があります。

クエリパラメータって何?

クエリパラメータは、URLの後ろに?記号に続けて付けられる一連のキーと値のペアで、リソースを特定するためや、リクエストの詳細情報を伝えるために使用されます。各キーと値のペアは=で結び付けられ、複数のペアは&で区切られます。

クエリパラメータの例

https://example.com/search?query=chatbot&sort=date

ここで、queryとsortはクエリパラメータのキーであり、それぞれのキーにはchatbotとdateという値が関連付けられています。

クエリパラメータは以下のような用途でよく使われます

検索クエリ: ウェブサイトの検索バーで検索を行うと、その検索クエリはクエリパラメータとしてURLに追加されることがよくあります。

ページネーション: 一覧表示画面でページを移動する際、どのページを表示するかを示すためにクエリパラメータが使用されます。

フィルタリング: 一覧表示画面で特定の条件でアイテムをフィルタリングする場合、その条件をクエリパラメータとしてURLに追加することがあります。

設定や状態の保存: ユーザーの設定や現在のアプリケーションの状態をURLに保存するためにクエリパラメータが使われることもあります。

クエリパラメータは、URLの一部としてブラウザやAPIクライアントからサーバに送信され、サーバ側のプログラム(例えばWebサーバやAPIエンドポイント)でその情報を受け取って処理を行うことができます。

sayasaya

ファイル名取得パターン1

Azure Functions の Blob Storage トリガー:

Azure Functionsを用いると、Blob Storageに新しいファイルがアップロードされたときに特定の関数を自動的に実行することができます。

このトリガー機能を使用すると、関数内でアップロードされたファイルの名前や内容を直接取得することができます。

Blob Storageに新しいBlobが追加されたときに実行されるBlobトリガー関数の一例
import azure.functions as func

def main(myblob: func.InputStream, name: str):
    logging.info(f"Python blob trigger function processed blob \n Name: {name} \n Data: {myblob.read()}")

⬆️
API Managementを通じてAzure Functionが呼び出されている場合、Blob トリガーを使用してファイル名を取得するのは冗長では?
(Blob トリガー自体は、Blob に変更があったときに自動的に関数を実行するためのもの。すでに別の方法(API Management経由)で関数をトリガーしている場合、Blob トリガーは必須ではない。)

ファイル名取得パターン2

API呼び出し時にファイル名を渡す

API ManagementからAzure Functionを呼び出すときに、ファイル名やBlobのURLをパラメータとして渡す方法です。この方法では、Azure FunctionはAPIから直接ファイル名を取得することができ、Blobから該当のデータを読み取る際にそのファイル名を使用できます。

ファイル名取得パターン3

Azure Storage SDKを使用する

Azure Storage SDKを使用して、特定のBlob Container内のBlobのリストを取得し、それを基に処理を行う方法です。ただし、この方法は特定のBlobをターゲットにする場合には効率的ではないかもしれません。

ファイル名取得パターン4

メタデータの利用
Blobをアップロードする際に、関連するメタデータ(例:ファイル名)をBlobに付与することができます。このメタデータは後で読み取ることができるため、API Managementから関数を呼び出す際に特定のBlobのメタデータを基に処理を行うことができます。

sayasaya

ファイル名取得パターン2について

API Managementを使用してAzure Functionを呼び出す際にファイル名をパラメータとして渡す方法

ステップ1: API ManagementのAPI定義

Azure PortalのAPI Managementサービスにログインします。
左側のメニューから「API」を選択し、既存のAPIを編集するか、新しいAPIを作成します。
APIのエンドポイントURLを定義します。例: https://your-apim-service-name.azure-api.net/myapi
このAPIに新しい操作(例:GETやPOST)を追加します。
操作の「バックエンド」セクションで、Azure FunctionsのURLを指定します。例: https://your-azure-function-app.azurewebsites.net/api/YourFunctionName
クエリパラメータとしてfilenameを追加します。このfilenameはAPIの利用者がAPIを呼び出す際に指定するパラメータとなります。

ステップ2: Azure Functionの変更

Azure Function内で、クエリパラメータとして渡されるfilenameを取得するように関数を変更します。

例えば、PythonのAzure Functionsであれば次のようになります:

import azure.functions as func

def main(req: func.HttpRequest) -> func.HttpResponse:
    # クエリパラメータからファイル名を取得
    filename = req.params.get('filename')

    if not filename:
        return func.HttpResponse("Filename not provided", status_code=400)

    # 以降の処理でfilenameを利用してBlobからデータを取得するなどの操作を行います...

    return func.HttpResponse(f"Processing file: {filename}")

ステップ3: APIの利用

APIを利用するクライアント(例えば、PowerAppsや他のWebアプリケーションなど)は、API ManagementのエンドポイントURLを使用してAPIを呼び出し、必要なパラメータを指定します。

例:

https://your-apim-service-name.azure-api.net/myapi?filename=sample-blob.txt

上記のURLを使用してAPIを呼び出すと、filenameとしてsample-blob.txtがAzure Function
に渡され、関数はこのファイル名に基づいて必要な処理を実行します。

APIの利用者が特定のBlobファイルを指定して処理を実行することができるようになります。

sayasaya

最終的にこの方法がいいのでは?ってやつ

  1. Power Appsのファイルアップロード機能: Power Appsにはファイルをアップロードするためのコントロールがあります。ユーザがこのコントロールを使用してファイルをアップロードすると、そのファイルの名前や内容を取得することができます。

  2. ファイルのBlob Storageへのアップロード: Power AppsからAzure FunctionsまたはLogic Appにファイルを送信し、そこでBlob Storageにファイルを保存します。このとき、ファイル名やその他のメタデータも一緒に送ることができます。

  3. API Managementを通じてAzure Functionsを起動: Power Appsから、API Managementのエンドポイントに対してHTTPリクエストを送信します。このリクエストには、先程Blob Storageにアップロードしたファイルの名前やパスなどの情報をクエリパラメータとして含めます。

  4. Durable Functionsを使用した処理: Azure Functions内でDurable Functionsを使用して、長時間実行される処理を管理します。この処理が終了すると、Power Appsに結果を返すことができます。

具体的な実装方法は以下の通り

  1. Power Appsでファイルアップロードコントロールを使用して、ファイルとその名前を取得します。
  2. Power Appsのボタンアクションなどで、Azure FunctionsやLogic Appのエンドポイントを呼び出し、ファイルとその名前を渡します。
  3. Azure FunctionsやLogic Appで、取得したファイルをBlob Storageに保存します。
  4. 同じAzure Functionsまたは別のエンドポイントを使用して、API Managementのエンドポイントを呼び出し、Blobのパスやファイル名などの情報をクエリパラメータとして渡します。
  5. API Managementを通じて起動されたAzure Functions(Durable Functions)で、長時間実行される処理を開始します。
  6. 処理が終了すると、結果をPower Appsに返します。

この方法を使用すると、Power Appsからファイルをアップロードし、そのファイル名や内容に基づいてAzure Functionsで処理を行い、結果をPower Appsに返すという流れを自動化することができます。

クエリパラメータとして毎回変わるファイルの名前を指定できるのか?

Power Appsから、API Managementのエンドポイントに対してHTTPリクエストを送信する処理ってどうやるの?クエリパラメータとして毎回変わるファイルの名前を指定できるの?

Power Apps から外部の API エンドポイント(この場合は API Management のエンドポイント)を呼び出すには、Power Apps の「データ接続」や「カスタム コネクタ」を使用します。

以下にその手順を示します:

  1. カスタム コネクタの作成:
    Power Apps の管理センターに移動します。
    「カスタム コネクタ」のセクションを選択し、新しいカスタム コネクタを作成します。
    コネクタの設定ページで、API Management のエンドポイントの情報を入力します。

  2. APIの定義:
    「アクションの定義」のセクションで、新しいアクションを追加します。
    API のエンドポイント URL を入力します。この URL にはクエリパラメータを含めることができます。
    パラメータとして「filename」を追加します。このパラメータは動的に設定できるようになります。

  3. Power Apps でのカスタム コネクタの使用
    Power Apps スタジオに戻り、アプリを編集します。
    「データ」タブから、作成したカスタム コネクタをアプリに追加します。
    ボタンやその他のコントロールのアクションとして、カスタム コネクタの API を呼び出すロジックを追加します。このとき、動的に「filename」の値を設定することができます。

具体的には、ファイルをアップロードするためのコントロールから取得したファイル名を、カスタム コネクタを通じて API Management のエンドポイントに渡すことができます。ファイル名は動的に変わるため、アップロードアクションの中でその都度取得して、API のクエリパラメータとして指定することができます。

この方法を使用すると、Power Apps から動的な値を持つクエリパラメータを持つ API Management のエンドポイントを呼び出すことが可能となります。

https://zenn.dev/link/comments/15e281fd74fb89

sayasaya

azure functionsのクライアント関数をapi manegementでどう呼び出すの?

Azure API Management (APIM) を使用して Azure Functions を呼び出す場合、以下のステップに従います。

  1. Azure Functions の設定:

Azure Functions で HTTP トリガーを使用して関数を作成します。
Function App の「プラットフォーム機能」セクションから「API」定義を選択し、API の定義を生成します。これにより、Azure Functions の Swagger 定義が生成されます。

  1. Azure API Management インスタンスの作成:

APIM インスタンスを作成します。

  1. API のインポート:

APIM のブレードに移動し、「API」セクションに移動します。
「API の追加」を選択し、「OpenAPI」や「WADL」のような関数の定義形式に基づいて関数をインポートします。
先ほど Azure Functions から取得した Swagger 定義の URL や JSON ファイルを指定します。

  1. バックエンド設定:

API の設定を開き、「デザイン」セクションにある「バックエンド」を選択します。
ここで Azure Functions の URL をバックエンドサービスとして指定します。

  1. ポリシーの設定(オプション):

必要に応じて、各 API エンドポイントにポリシーを追加します。例えば、Azure Functions のキーをヘッダに追加することで認証を行うなど。

  1. テスト:

API Management ポータル内で、新しく追加された API エンドポイントをテストします。これにより、Azure Functions が正しく呼び出されることを確認できます。

  1. フロントエンドアプリケーションの更新:

アプリケーションのエンドポイントを、直接の Azure Functions の URL から、API Management を経由する URL に変更します。

これで、Azure API Management を通じて Azure Functions を呼び出す設定が完了しました。APIM を使用することで、関数の呼び出しに対して追加のポリシー、レート制限、キャッシングなどの機能を簡単に追加することができます。