Skip to content

Commit 7a231ca

Browse files
Learn Build Service GitHub AppLearn Build Service GitHub App
authored andcommitted
Merging changes synced from https://github.com/MicrosoftDocs/azure-dev-docs-pr (branch live)
2 parents fe18b60 + daed32f commit 7a231ca

File tree

9 files changed

+1758
-1
lines changed

9 files changed

+1758
-1
lines changed

articles/github-copilot-azure/TOC.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,6 @@ items:
3030
expanded: true
3131
items:
3232
- name: Create Bicep files
33-
href: bicep-generate-edit.md
33+
href: bicep-generate-edit.md
34+
- name: Generate and deploy a Django / PostgreSQL app
35+
href: generate-deploy-django-postgresql.md

articles/github-copilot-azure/generate-deploy-django-postgresql.md

Lines changed: 288 additions & 0 deletions
Large diffs are not rendered by default.

articles/github-copilot-azure/index.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ landingContent:
2323
url: get-started.md
2424
- text: Quickstart - Building, Deploying and Improving your application with GitHub Copilot for Azure
2525
url: quickstart-build-deploy-applications.md
26+
- text: Generate and deploy a Django / PostgreSQL app
27+
url: generate-deploy-django-postgresql.md
2628

2729
- title: Prompts for Azure
2830
linkLists:

articles/python/TOC.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,18 @@
205205
href: sdk/azure-sdk-configure-proxy.md
206206
- name: Use a sovereign domain
207207
href: sdk/azure-sdk-sovereign-domain.md
208+
- name: SDK Fundamentals
209+
items:
210+
- name: Overview
211+
href: sdk/Fundamentals/overview.md
212+
- name: Errors
213+
href: sdk/Fundamentals/errors.md
214+
- name: HTTP Pipeline & retries
215+
href: sdk/Fundamentals/http-pipeline-retries.md
216+
- name: Common Types (Response)
217+
href: sdk/Fundamentals/common-types-response.md
218+
- name: Language design guidelines
219+
href: sdk/Fundamentals/language-design-guidelines.md
208220
- name: SDK PyPI package index
209221
href: sdk/azure-sdk-library-package-index.md
210222
- name: SDK reference documentation
Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,339 @@
1+
---
2+
title: Understanding common response types in the Azure SDK for Python
3+
description: Learn types of objects you receive from SDK operations when using the Azure SDK for Python.
4+
ms.date: 7/10/2025
5+
ms.topic: conceptual
6+
ms.custom: devx-track-python, py-fresh-zinc
7+
---
8+
9+
# Understanding common response types in the Azure SDK for Python
10+
11+
The Azure SDK for Python abstracts calls to the underlying Azure service communication protocol, whether that protocol is HTTP or AMQP (which is used for messaging SDKs like ServiceBus, EventHubs, etc.). For example, if you use one of the libraries that utilizes HTTP, then the Azure SDK for Python is making HTTP requests and receiving HTTP responses under the hood. The SDK abstracts away this complexity, allowing you to work with intuitive Python objects instead of raw HTTP responses or JSON payloads.
12+
13+
Understanding the types of objects you receive from SDK operations is essential for writing effective Azure applications. This article explains the common response types you encounter and how they relate to the underlying HTTP communication.
14+
15+
> [!NOTE]
16+
> This article only examines the HTTP scenario, not the AMQP scenario.
17+
18+
## Deserialized Python objects
19+
20+
The Azure SDK for Python prioritizes developer productivity by returning strongly typed Python objects from service operations. Instead of parsing JSON or handling HTTP status codes directly, you work with resource models that represent Azure resources as Python objects.
21+
22+
For example, when you retrieve a blob from Azure Storage, you receive a BlobProperties object with attributes like name, size, and last_modified, rather than a raw JSON dictionary:
23+
24+
```python
25+
from azure.storage.blob import BlobServiceClient
26+
27+
# Connect to storage account
28+
blob_service_client = BlobServiceClient.from_connection_string(connection_string)
29+
container_client = blob_service_client.get_container_client("mycontainer")
30+
31+
# Get blob properties - returns a BlobProperties object
32+
blob_client = container_client.get_blob_client("myblob.txt")
33+
properties = blob_client.get_blob_properties()
34+
35+
# Access properties as Python attributes
36+
print(f"Blob name: {properties.name}")
37+
print(f"Blob size: {properties.size} bytes")
38+
print(f"Last modified: {properties.last_modified}")
39+
```
40+
41+
### Where the data comes from
42+
43+
Understanding the data flow helps you appreciate what the SDK does behind the scenes:
44+
45+
- Your code calls an SDK method - You invoke a method like get_blob_properties()
46+
- The SDK constructs an HTTP request - The SDK builds the appropriate HTTP request with headers, authentication, and query parameters
47+
- Azure service responds - The service returns an HTTP response, typically with a JSON payload in the response body
48+
- The SDK processes the response - The SDK:
49+
- Checks the HTTP status code
50+
- Parses the response body (usually JSON)
51+
- Validates the data against expected schemas
52+
- Maps the data to Python model objects
53+
- Your code receives Python objects - You work with the deserialized objects, not raw HTTP data
54+
55+
This abstraction allows you to focus on your application logic rather than HTTP protocol details.
56+
57+
## Common response types
58+
59+
The Azure SDK for Python uses several standard response types across all services. Understanding these types helps you work effectively with any Azure service.
60+
61+
### Resource models
62+
63+
Most SDK operations return resource models—Python objects that represent Azure resources. These models are service-specific but follow consistent patterns:
64+
65+
```python
66+
# Azure Key Vault example
67+
from azure.keyvault.secrets import SecretClient
68+
69+
secret_client = SecretClient(vault_url=vault_url, credential=credential)
70+
secret = secret_client.get_secret("mysecret") # Returns KeyVaultSecret
71+
72+
print(f"Secret name: {secret.name}")
73+
print(f"Secret value: {secret.value}")
74+
print(f"Secret version: {secret.properties.version}")
75+
76+
# Azure Cosmos DB example
77+
from azure.cosmos import CosmosClient
78+
79+
cosmos_client = CosmosClient(url=cosmos_url, credential=credential)
80+
database = cosmos_client.get_database_client("mydatabase")
81+
container = database.get_container_client("mycontainer")
82+
item = container.read_item(item="item-id", partition_key="partition-value") # Returns dict
83+
84+
print(f"Item ID: {item['id']}")
85+
```
86+
87+
### ItemPaged for collection results
88+
89+
When listing resources, the SDK returns `ItemPaged` objects that handle pagination transparently:
90+
91+
```python
92+
from azure.storage.blob import BlobServiceClient
93+
from azure.core.paging import ItemPaged
94+
95+
blob_service_client = BlobServiceClient.from_connection_string(connection_string)
96+
container_client = blob_service_client.get_container_client("mycontainer")
97+
98+
# list_blobs returns ItemPaged[BlobProperties]
99+
blobs: ItemPaged[BlobProperties] = container_client.list_blobs()
100+
101+
# Iterate naturally - SDK handles pagination
102+
for blob in blobs:
103+
print(f"Blob: {blob.name}, Size: {blob.size}")
104+
```
105+
106+
## Accessing the raw HTTP response
107+
108+
While the SDK's high-level abstractions meet most needs, you sometimes need access to the underlying HTTP response. Common scenarios include:
109+
110+
- Debugging failed requests
111+
- Accessing custom response headers
112+
- Implementing custom retry logic
113+
- Working with nonstandard response formats
114+
115+
Most SDK methods accept a `raw_response_hook` parameter:
116+
117+
```python
118+
from azure.keyvault.secrets import SecretClient
119+
120+
secret_client = SecretClient(vault_url=vault_url, credential=credential)
121+
122+
def inspect_response(response):
123+
# Access the raw HTTP response
124+
print(f"Request URL: {response.http_request.url}")
125+
print(f"Status code: {response.http_response.status_code}")
126+
print(f"Response headers: {dict(response.http_response.headers)}")
127+
128+
# Access custom headers
129+
request_id = response.http_response.headers.get('x-ms-request-id')
130+
print(f"Request ID: {request_id}")
131+
132+
# Must return the response
133+
return response
134+
135+
# Hook is called before deserialization
136+
secret = secret_client.get_secret("mysecret", raw_response_hook=inspect_response)
137+
```
138+
139+
## Paging and iterators
140+
141+
Azure services often return large collections of resources. The SDK uses ItemPaged to handle these collections efficiently without loading everything into memory at once.
142+
143+
### Automatic pagination
144+
145+
The SDK automatically fetches new pages as you iterate:
146+
147+
```python
148+
# List all blobs - could be thousands
149+
blobs = container_client.list_blobs()
150+
151+
# SDK fetches pages as needed during iteration
152+
for blob in blobs:
153+
process_blob(blob) # Pages loaded on-demand
154+
```
155+
156+
### Working with pages explicitly
157+
158+
You can also work with pages directly when needed:
159+
160+
```python
161+
blobs = container_client.list_blobs()
162+
163+
# Process by page
164+
for page in blobs.by_page():
165+
print(f"Processing page with {len(list(page))} items")
166+
for blob in page:
167+
process_blob(blob)
168+
```
169+
170+
### Controlling page size
171+
172+
Many list operations accept a results_per_page parameter:
173+
174+
```python
175+
# Fetch 100 items per page instead of the default
176+
blobs = container_client.list_blobs(results_per_page=100)
177+
```
178+
179+
Some methods for some Azure services have other mechanisms for controlling page size. For example, KeyVault and Azure Search use the `top` kwarg to limit results per call. See the [source code](https://github.com/Azure/azure-sdk-for-python/blob/0cf4523c054fc793c6ce46616daa5e23f9607d33/sdk/search/azure-search-documents/azure/search/documents/_search_client.py#L174) for Azure Search's `search()` method as an example.
180+
181+
182+
## Special case: Long-running operations and pollers
183+
184+
185+
Some Azure operations can't complete immediately. Examples include:
186+
187+
- Creating or deleting virtual machines
188+
- Deploying ARM templates
189+
- Training machine learning models
190+
- Copying large blobs
191+
192+
These operations return poller objects that track the operation's progress.
193+
194+
### Working with pollers
195+
196+
```python
197+
from azure.mgmt.storage import StorageManagementClient
198+
199+
storage_client = StorageManagementClient(credential, subscription_id)
200+
201+
# Start storage account creation
202+
poller = storage_client.storage_accounts.begin_create(
203+
resource_group_name="myresourcegroup",
204+
account_name="mystorageaccount",
205+
parameters=storage_parameters
206+
)
207+
208+
# Option 1: Wait for completion (blocking)
209+
storage_account = poller.result()
210+
211+
# Option 2: Check status periodically
212+
while not poller.done():
213+
print(f"Status: {poller.status()}")
214+
time.sleep(5)
215+
216+
storage_account = poller.result()
217+
```
218+
219+
### Asynchronous pollers
220+
221+
When using async/await patterns, you work with `AsyncLROPoller`:
222+
223+
```python
224+
from azure.storage.blob.aio import BlobServiceClient
225+
226+
async with BlobServiceClient.from_connection_string(connection_string) as client:
227+
container_client = client.get_container_client("mycontainer")
228+
229+
# Start async copy operation
230+
blob_client = container_client.get_blob_client("large-blob.vhd")
231+
poller = await blob_client.begin_copy_from_url(source_url)
232+
233+
# Wait for async completion
234+
copy_properties = await poller.result()
235+
```
236+
237+
### Polling objects for long-running operations example: Virtual Machines
238+
239+
Deploying Virtual Machines in an example of an operation that takes time to complete and handles it by returning poller objects (LROPoller for synchronous code, AsyncLROPoller for asynchronous code):
240+
241+
```python
242+
from azure.mgmt.compute import ComputeManagementClient
243+
from azure.core.polling import LROPoller
244+
245+
compute_client = ComputeManagementClient(credential, subscription_id)
246+
247+
# Start VM creation - returns immediately with a poller
248+
poller: LROPoller = compute_client.virtual_machines.begin_create_or_update(
249+
resource_group_name="myresourcegroup",
250+
vm_name="myvm",
251+
parameters=vm_parameters
252+
)
253+
254+
# Wait for completion and get the result
255+
vm = poller.result() # Blocks until operation completes
256+
print(f"VM {vm.name} provisioned successfully")
257+
```
258+
259+
### Accessing response for paged results
260+
261+
For paged results, use the `by_page()` method with `raw_response_hook`:
262+
263+
```python
264+
def page_response_hook(response):
265+
continuation_token = response.http_response.headers.get('x-ms-continuation')
266+
print(f"Continuation token: {continuation_token}")
267+
return response
268+
269+
blobs = container_client.list_blobs()
270+
for page in blobs.by_page(raw_response_hook=page_response_hook):
271+
for blob in page:
272+
print(blob.name)
273+
```
274+
275+
## Best practices
276+
277+
- **Prefer high-level abstractions**
278+
- **Work with the SDK's resource models rather than raw responses** whenever possible, and **avoid accessing any method prefixed with an underscore `_`** since, by convention, those are private in Python. There are no guarantees about breaking changes, etc. compared to public APIs:
279+
280+
```python
281+
# Preferred: Work with typed objects
282+
secret = secret_client.get_secret("mysecret")
283+
if secret.properties.enabled:
284+
use_secret(secret.value)
285+
286+
# Avoid: Manual JSON parsing (unless necessary) ...
287+
# AND avoid accessing any objects or methods that start with `_`
288+
response = secret_client._client.get(...) # Don't access internal clients
289+
data = json.loads(response.text)
290+
if data['attributes']['enabled']:
291+
use_secret(data['value'])
292+
```
293+
294+
295+
296+
- **Handle pagination properly** - Always iterate over paged results instead of converting to a list:
297+
298+
```python
299+
# Good: Memory-efficient iteration
300+
for blob in container_client.list_blobs():
301+
process_blob(blob)
302+
303+
# Avoid: Loading everything into memory
304+
all_blobs = list(container_client.list_blobs()) # Could consume excessive memory
305+
```
306+
307+
- **Use `poller.result()` for long-running operations** - Always use the `result()` method to ensure operations complete successfully:
308+
309+
```python
310+
# Correct: Wait for operation completion
311+
poller = compute_client.virtual_machines.begin_delete(
312+
resource_group_name="myresourcegroup",
313+
vm_name="myvm"
314+
)
315+
poller.result() # Ensures deletion completes
316+
print("VM deleted successfully")
317+
318+
# Wrong: Assuming immediate completion
319+
poller = compute_client.virtual_machines.begin_delete(...)
320+
print("VM deleted successfully") # Deletion might still be in progress!
321+
```
322+
323+
- **Access raw responses only when needed** - Use raw response access sparingly and only for specific requirements:
324+
325+
```python
326+
# Good use case: Debugging or logging
327+
def log_request_id(response):
328+
request_id = response.http_response.headers.get('x-ms-request-id')
329+
logger.info(f"Operation request ID: {request_id}")
330+
return response
331+
332+
blob_client.upload_blob(data, raw_response_hook=log_request_id)
333+
334+
# Good use case: Custom error handling
335+
def check_custom_header(response):
336+
if response.http_response.headers.get('x-custom-error'):
337+
raise CustomApplicationError("Custom error condition detected")
338+
return response
339+
```

0 commit comments

Comments
 (0)