Azure SDK for Python の一般的な応答の種類について

Azure SDK for Python は、基になる Azure サービス通信プロトコルの呼び出しを抽象化します。そのプロトコルが HTTP であるか AMQP であるか ( ServiceBus や EventHubsなどのメッセージング SDK に使用されます)。 たとえば、HTTP を使用するライブラリのいずれかを使用する場合、Azure SDK for Python は HTTP 要求を行い、内部で HTTP 応答を受信します。 SDK は、生の HTTP 応答や JSON ペイロードではなく、直感的な Python オブジェクトを操作できるように、この複雑さを抽象化します。

SDK 操作から受け取るオブジェクトの種類を理解することは、効果的な Azure アプリケーションを作成するために不可欠です。 この記事では、発生する一般的な応答の種類と、それらが基になる HTTP 通信にどのように関連しているかを説明します。

注

この記事では、AMQP シナリオではなく、HTTP シナリオのみを調べます。

逆シリアル化された Python オブジェクト

Azure SDK for Python は、サービス操作から厳密に型指定された Python オブジェクトを返すことで、開発者の生産性に優先順位を付けます。 JSON を解析したり、HTTP 状態コードを直接処理したりする代わりに、Azure リソースを Python オブジェクトとして表すリソース モデルを使用します。

たとえば、Azure Storage から BLOB を取得すると、未加工の JSON ディクショナリではなく、BlobProperties、name、sizeなどの属性を持つlast_modified オブジェクトを受け取ります。

from azure.storage.blob import BlobServiceClient

# Connect to storage account
blob_service_client = BlobServiceClient.from_connection_string(connection_string)
container_client = blob_service_client.get_container_client("mycontainer")

# Get blob properties - returns a BlobProperties object
blob_client = container_client.get_blob_client("myblob.txt")
properties = blob_client.get_blob_properties()

# Access properties as Python attributes
print(f"Blob name: {properties.name}")
print(f"Blob size: {properties.size} bytes")
print(f"Last modified: {properties.last_modified}")

データの取得元

データ フローを理解すると、SDK がバックグラウンドで行うことを理解するのに役立ちます。

  • コードで SDK メソッドを呼び出します。get_blob_properties()などのメソッドを呼び出します。
  • SDK は HTTP 要求を構築します。 SDK は、ヘッダー、認証、およびクエリ パラメーターを使用して適切な HTTP 要求をビルドします。
  • Azure サービスは次のように応答します。 サービスは HTTP 応答を返します。通常は、応答本文に JSON ペイロードが含まれます。
  • SDK は応答を処理します。 The SDK:
    • HTTP 状態コードを確認します。
    • 応答本文 (通常は JSON) を解析します。
    • 予想されるスキーマに対してデータを検証します。
    • データを Python モデル オブジェクトにマップします。
  • コードは Python オブジェクトを受け取ります。 未加工の HTTP データではなく、逆シリアル化されたオブジェクトを操作します。

この抽象化により、HTTP プロトコルの詳細ではなく、アプリケーション ロジックに集中できます。

一般的な応答の種類

Azure SDK for Python では、すべてのサービスで複数の標準応答の種類が使用されます。 これらの種類を理解することは、任意の Azure サービスを効果的に操作するのに役立ちます。

リソース モデル

ほとんどの SDK 操作では、リソース モデルが返されます。 これらの Python オブジェクトは、Azure リソースを表します。 モデルはサービス固有ですが、一貫したパターンに従います。

# Azure Key Vault example
from azure.keyvault.secrets import SecretClient

secret_client = SecretClient(vault_url=vault_url, credential=credential)
secret = secret_client.get_secret("mysecret")  # Returns KeyVaultSecret

print(f"Secret name: {secret.name}")
print(f"Secret value: {secret.value}")
print(f"Secret version: {secret.properties.version}")

# Azure Cosmos DB example
from azure.cosmos import CosmosClient

cosmos_client = CosmosClient(url=cosmos_url, credential=credential)
database = cosmos_client.get_database_client("mydatabase")
container = database.get_container_client("mycontainer")
item = container.read_item(item="item-id", partition_key="partition-value")  # Returns dict

print(f"Item ID: {item['id']}")

コレクション結果の ItemPaged

SDK はリソースを一覧表示すると、改ページ位置を透過的に処理する ItemPaged オブジェクトを返します。

from azure.storage.blob import BlobServiceClient
from azure.core.paging import ItemPaged

blob_service_client = BlobServiceClient.from_connection_string(connection_string)
container_client = blob_service_client.get_container_client("mycontainer")

# list_blobs returns ItemPaged[BlobProperties]
blobs: ItemPaged[BlobProperties] = container_client.list_blobs()

# Iterate naturally - SDK handles pagination
for blob in blobs:
    print(f"Blob: {blob.name}, Size: {blob.size}")

生の HTTP 応答にアクセスする

SDK の高度な抽象化はほとんどのニーズを満たしますが、基になる HTTP 応答へのアクセスが必要な場合があります。 一般的なシナリオは、次のとおりです。

  • 失敗した要求のデバッグ。
  • カスタム応答ヘッダーへのアクセス。
  • カスタム再試行ロジックの実装。
  • 標準以外の応答形式を扱うこと。

ほとんどの SDK メソッドでは、 raw_response_hook パラメーターを受け取ります。

from azure.keyvault.secrets import SecretClient

secret_client = SecretClient(vault_url=vault_url, credential=credential)

def inspect_response(response):
    # Access the raw HTTP response
    print(f"Request URL: {response.http_request.url}")
    print(f"Status code: {response.http_response.status_code}")
    print(f"Response headers: {dict(response.http_response.headers)}")
    
    # Access custom headers
    request_id = response.http_response.headers.get('x-ms-request-id')
    print(f"Request ID: {request_id}")
    
    # Must return the response
    return response

# Hook is called before deserialization
secret = secret_client.get_secret("mysecret", raw_response_hook=inspect_response)

ページングと反復子

多くの場合、Azure サービスは大量のリソースを返します。 SDK では、 ItemPaged を使用して、すべてを一度にメモリに読み込まずに、これらのコレクションを効率的に処理します。

自動改ページ

反復処理を行うと、SDK によって新しいページが自動的にフェッチされます。

# List all blobs - could be thousands
blobs = container_client.list_blobs()

# SDK fetches pages as needed during iteration
for blob in blobs:
    process_blob(blob)  # Pages loaded on-demand

明示的にページを扱う

必要に応じて、ページを直接操作することもできます。

blobs = container_client.list_blobs()

# Process by page
for page in blobs.by_page():
    print(f"Processing page with {len(list(page))} items")
    for blob in page:
        process_blob(blob)

ページ サイズを制御する

多くのリスト操作では、 results_per_page パラメーターを受け入れます。

# Fetch 100 items per page instead of the default
blobs = container_client.list_blobs(results_per_page=100)

一部の Azure サービスの一部の方法には、ページ サイズを制御するための他のメカニズムがあります。 たとえば、Azure Key Vault と Azure Search では、 top kwarg を使用して、呼び出しごとの結果を制限します。 Azure Search search() メソッドを使用する例については、 ソース コードを参照してください。

特殊なケース: 実行時間の長い操作とポーリング

一部の Azure 操作はすぐに完了できません。 たとえば、次のようになります。

  • 仮想マシンの作成または削除。
  • Azure Resource Manager テンプレートのデプロイ。
  • 機械学習モデルのトレーニング。
  • 大容量 BLOB のコピー。

これらの操作は、操作の進行状況を追跡するポーリング オブジェクトを返します。

投票者を操作する

from azure.mgmt.storage import StorageManagementClient

storage_client = StorageManagementClient(credential, subscription_id)

# Start storage account creation
poller = storage_client.storage_accounts.begin_create(
    resource_group_name="myresourcegroup",
    account_name="mystorageaccount",
    parameters=storage_parameters
)

# Option 1: Wait for completion (blocking)
storage_account = poller.result()

# Option 2: Check status periodically
while not poller.done():
    print(f"Status: {poller.status()}")
    time.sleep(5)

storage_account = poller.result()

非同期ポーリング

async/await パターンを使用する場合は、 AsyncLROPollerを操作します。

from azure.storage.blob.aio import BlobServiceClient

async with BlobServiceClient.from_connection_string(connection_string) as client:
    container_client = client.get_container_client("mycontainer")
    
    # Start async copy operation
    blob_client = container_client.get_blob_client("large-blob.vhd")
    poller = await blob_client.begin_copy_from_url(source_url)
    
    # Wait for async completion
    copy_properties = await poller.result()

実行時間の長い操作のオブジェクトのポーリングの例: 仮想マシン

仮想マシンのデプロイは、完了に時間がかかり、ポーリング オブジェクト (同期コードの場合はLROPoller 、非同期コードの場合は AsyncLROPoller ) を返すことによって処理する操作の例です。

from azure.mgmt.compute import ComputeManagementClient
from azure.core.polling import LROPoller

compute_client = ComputeManagementClient(credential, subscription_id)

# Start VM creation - returns immediately with a poller
poller: LROPoller = compute_client.virtual_machines.begin_create_or_update(
    resource_group_name="myresourcegroup",
    vm_name="myvm",
    parameters=vm_parameters
)

# Wait for completion and get the result
vm = poller.result()  # Blocks until operation completes
print(f"VM {vm.name} provisioned successfully")

ページ分割された結果へのアクセス応答

ページングされた結果の場合は、by_page()で raw_response_hook メソッドを使用します。

def page_response_hook(response):
    continuation_token = response.http_response.headers.get('x-ms-continuation')
    print(f"Continuation token: {continuation_token}")
    return response

blobs = container_client.list_blobs()
for page in blobs.by_page(raw_response_hook=page_response_hook):
    for blob in page:
        print(blob.name)

ベスト プラクティス

  • 高度な抽象化を優先します。

  • 可能な限り生の応答ではなく、SDK のリソース モデルを操作します。

  • アンダースコア (_) が付いたメソッドにはアクセスしないでください。 慣例により、これらのメソッドは Python ではプライベートです。 パブリック API と比較した破壊的変更などの問題に関する保証はありません。

    # Preferred: Work with typed objects
    secret = secret_client.get_secret("mysecret")
    if secret.properties.enabled:
        use_secret(secret.value)
    
    # Avoid: Manual JSON parsing (unless necessary) ...
    # AND avoid accessing any objects or methods that start with `_`
    response = secret_client._client.get(...)  # Don't access internal clients
    data = json.loads(response.text)
    if data['attributes']['enabled']:
        use_secret(data['value'])
    
  • 改ページ位置を適切に処理します。 リストに変換するのではなく、常にページングされた結果を反復処理します。

    # Good: Memory-efficient iteration
    for blob in container_client.list_blobs():
        process_blob(blob)
    
    # Avoid: Loading everything into memory
    all_blobs = list(container_client.list_blobs())  # Could consume excessive memory
    
  • 実行時間の長い操作には poller.result() を使用します。 操作が正常に完了することを確認するには、常に result() メソッドを使用します。

    # Correct: Wait for operation completion
    poller = compute_client.virtual_machines.begin_delete(
        resource_group_name="myresourcegroup",
        vm_name="myvm"
    )
    poller.result()  # Ensures deletion completes
    print("VM deleted successfully")
    
    # Wrong: Assuming immediate completion
    poller = compute_client.virtual_machines.begin_delete(...)
    print("VM deleted successfully")  # Deletion might still be in progress!
    
  • 必要な場合にのみ生の応答にアクセスします。 生の応答アクセスを慎重に使用し、特定の要件に対してのみ使用します。

    # Good use case: Debugging or logging
    def log_request_id(response):
        request_id = response.http_response.headers.get('x-ms-request-id')
        logger.info(f"Operation request ID: {request_id}")
        return response
    
    blob_client.upload_blob(data, raw_response_hook=log_request_id)
    
    # Good use case: Custom error handling
    def check_custom_header(response):
        if response.http_response.headers.get('x-custom-error'):
            raise CustomApplicationError("Custom error condition detected")
        return response