Azure Cosmos DB Py
MicrosoftOfficialCreated by Microsoft
- Skill
- Tool integration
- Software development
- MIT
- Low risk
- Has scripts
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides patterns and templates for integrating Azure Cosmos DB into Python and FastAPI applications. It focuses on secure authentication using DefaultAzureCredential, singleton client management, and service layer patterns for CRUD operations. The guidance includes strategies for partition key management, parameterized queries, and TDD-based testing using pytest.
What it does
- Provides a singleton pattern for Cosmos DB client initialization.
- Implements dual authentication for local emulator and Azure production environments.
- Wraps synchronous SDK calls for asynchronous execution in FastAPI.
- Defines a service layer pattern for document-to-model conversion.
- Offers templates for pytest fixtures to facilitate unit testing.
- Outlines error handling patterns for common Cosmos DB exceptions.
When to use it
- When building a FastAPI backend that requires NoSQL persistence with Azure Cosmos DB.
- When you need to implement secure, RBAC-based authentication for database access.
- When you want to structure your database interaction layer using service classes.
- When you need to write unit tests for code that interacts with the Cosmos DB SDK.
Advantages
- Promotes secure coding by using identity-based authentication instead of hardcoded keys.
- Ensures consistent connection management through singleton patterns.
- Facilitates testability by providing patterns for mocking database containers.
- Encourages clean code through separation of concerns between business logic and storage.
Usage examples
- “How do I set up a singleton Cosmos DB client in my FastAPI app?”
- The skill provides a module-level initialization pattern that uses DefaultAzureCredential for production and key-based auth for the local emulator.
- “Show me how to test a service layer method that reads from Cosmos DB.”
- The skill provides a pytest fixture template that uses mocking to simulate the Cosmos container, allowing you to test service logic without a live database.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/microsoft/azure-cosmos-db-py/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip azure-cosmos-db-py.zip -d .agents/skills
Documentation by Microsoft
Cosmos DB Service Implementation
Build production-grade Azure Cosmos DB NoSQL services following clean code, security best practices, and TDD principles.
Installation
pip install azure-cosmos azure-identityEnvironment Variables
COSMOS_ENDPOINT=https://<account>.documents.azure.com:443/ # Required for all auth methods
COSMOS_DATABASE_NAME=<database-name> # Required for all auth methods
COSMOS_CONTAINER_ID=<container-id> # Required for all auth methods
# For emulator only (not production)
COSMOS_KEY=<emulator-key> # Only required for key-based auth or emulator
AZURE_TOKEN_CREDENTIALS=prod # Required only if DefaultAzureCredential is used in productionAuthentication & Lifecycle
🔑 Two rules apply to every code sample below:
Prefer
DefaultAzureCredential. It works locally (Azure CLI / VS Code / Developer CLI) and in Azure (managed identity, workload identity) with no code change. Avoid connection strings, account/API keys — they bypass Entra audit and rotation.
Local dev:
DefaultAzureCredentialworks as-is.Production: set
AZURE_TOKEN_CREDENTIALS=prod(orAZURE_TOKEN_CREDENTIALS=<specific_credential>) to constrain the credential chain to production-safe credentials.Wrap every client in a context manager so HTTP transports, sockets, and token caches are released deterministically:
Sync:
with <Client>(...) as client:Async:
async with <Client>(...) as client:andasync with DefaultAzureCredential() as credential:(fromazure.identity.aio)Snippets may abbreviate this setup, but production code should always follow both rules.
DefaultAzureCredential (preferred):
import os
from azure.cosmos import CosmosClient
from azure.identity import DefaultAzureCredential, ManagedIdentityCredential
# Local dev: DefaultAzureCredential. Production: set AZURE_TOKEN_CREDENTIALS=prod or AZURE_TOKEN_CREDENTIALS=<specific_credential>
credential = DefaultAzureCredential(require_envvar=True)
# Or use a specific credential directly in production:
# See https://learn.microsoft.com/python/api/overview/azure/identity-readme?view=azure-python#credential-classes
# credential = ManagedIdentityCredential()
with CosmosClient(
url=os.environ["COSMOS_ENDPOINT"],
credential=credential
) as client:
# Use client here (see following sections for operations)
...Emulator (local development):
from azure.cosmos import CosmosClient
with CosmosClient(
url="https://localhost:8081",
credential=os.environ["COSMOS_KEY"],
connection_verify=False
) as client:
# Use client here (see following sections for operations)
...Architecture Overview
┌─────────────────────────────────────────────────────────────────┐
│ FastAPI Router │
│ - Auth dependencies (get_current_user, get_current_user_required)
│ - HTTP error responses (HTTPException) │
└──────────────────────────────┬──────────────────────────────────┘
│
┌──────────────────────────────▼──────────────────────────────────┐
│ Service Layer │
│ - Business logic and validation │
│ - Document ↔ Model conversion │
│ - Graceful degradation when Cosmos unavailable │
└──────────────────────────────┬──────────────────────────────────┘
│
┌──────────────────────────────▼──────────────────────────────────┐
│ Cosmos DB Client Module │
│ - Singleton container initialization │
│ - Dual auth: DefaultAzureCredential (Azure) / Key (emulator) │
│ - Async wrapper via run_in_threadpool │
└─────────────────────────────────────────────────────────────────┘Quick Start
1. Client Module Setup
Create a singleton Cosmos client with dual authentication:
# db/cosmos.py
from azure.cosmos import CosmosClient
from azure.identity import DefaultAzureCredential
from starlette.concurrency import run_in_threadpool
_cosmos_container = None
def _is_emulator_endpoint(endpoint: str) -> bool:
return "localhost" in endpoint or "127.0.0.1" in endpoint
async def get_container():
global _cosmos_container
if _cosmos_container is None:
# Singleton: client lives for the FastAPI app lifetime; close in a lifespan shutdown handler.
if _is_emulator_endpoint(settings.cosmos_endpoint):
client = CosmosClient(
url=settings.cosmos_endpoint,
credential=settings.cosmos_key,
connection_verify=False
)
else:
client = CosmosClient(
url=settings.cosmos_endpoint,
credential=DefaultAzureCredential()
)
db = client.get_database_client(settings.cosmos_database_name)
_cosmos_container = db.get_container_client(settings.cosmos_container_id)
return _cosmos_containerFull implementation: See references/client-setup.md
2. Pydantic Model Hierarchy
Use five-tier model pattern for clean separation:
class ProjectBase(BaseModel): # Shared fields
name: str = Field(..., min_length=1, max_length=200)
class ProjectCreate(ProjectBase): # Creation request
workspace_id: str = Field(..., alias="workspaceId")
class ProjectUpdate(BaseModel): # Partial updates (all optional)
name: Optional[str] = Field(None, min_length=1)
class Project(ProjectBase): # API response
id: str
created_at: datetime = Field(..., alias="createdAt")
class ProjectInDB(Project): # Internal with docType
doc_type: str = "project"3. Service Layer Pattern
class ProjectService:
def _use_cosmos(self) -> bool:
return get_container() is not None
async def get_by_id(self, project_id: str, workspace_id: str) -> Project | None:
if not self._use_cosmos():
return None
doc = await get_document(project_id, partition_key=workspace_id)
if doc is None:
return None
return self._doc_to_model(doc)Full patterns: See references/service-layer.md
Core Principles
Security Requirements
RBAC Authentication: Use
DefaultAzureCredentialin Azure — never store keys in codeEmulator-Only Keys: Hardcode the well-known emulator key only for local development
Parameterized Queries: Always use
@parametersyntax — never string concatenationPartition Key Validation: Validate partition key access matches user authorization
Clean Code Conventions
Single Responsibility: Client module handles connection; services handle business logic
Graceful Degradation: Services return
None/[]when Cosmos unavailableConsistent Naming:
_doc_to_model(),_model_to_doc(),_use_cosmos()Type Hints: Full typing on all public methods
CamelCase Aliases: Use
Field(alias="camelCase")for JSON serialization
TDD Requirements
Write tests BEFORE implementation using these patterns:
@pytest.fixture
def mock_cosmos_container(mocker):
container = mocker.MagicMock()
mocker.patch("app.db.cosmos.get_container", return_value=container)
return container
@pytest.mark.asyncio
async def test_get_project_by_id_returns_project(mock_cosmos_container):
# Arrange
mock_cosmos_container.read_item.return_value = {"id": "123", "name": "Test"}
# Act
result = await project_service.get_by_id("123", "workspace-1")
# Assert
assert result.id == "123"
assert result.name == "Test"Full testing guide: See references/testing.md
Best Practices
Pick sync OR async and stay consistent. Do not mix
azure.xxxsync clients withazure.xxx.aioasync clients in the same call path. Choose one mode per module.Always use context managers for clients and async credentials. Wrap the client in
async with CosmosClient(...) as client:(or manage its lifetime via FastAPI lifespan and close it explicitly). For asyncDefaultAzureCredentialfromazure.identity.aio, also useasync with credential:so tokens and transports are cleaned up.
Reference Files
| File | When to Read |
|---|---|
| references/client-setup.md | Setting up Cosmos client with dual auth, SSL config, singleton pattern |
| references/service-layer.md | Implementing full service class with CRUD, conversions, graceful degradation |
| references/testing.md | Writing pytest tests, mocking Cosmos, integration test setup |
| references/partitioning.md | Choosing partition keys, cross-partition queries, move operations |
| references/error-handling.md | Handling CosmosResourceNotFoundError, logging, HTTP error mapping |
Template Files
| File | Purpose |
|---|---|
| assets/cosmos_client_template.py | Ready-to-use client module |
| assets/service_template.py | Service class skeleton |
| assets/conftest_template.py | pytest fixtures for Cosmos mocking |
Quality Attributes (NFRs)
Reliability
Graceful degradation when Cosmos unavailable
Retry logic with exponential backoff for transient failures
Connection pooling via singleton pattern
Security
Zero secrets in code (RBAC via DefaultAzureCredential)
Parameterized queries prevent injection
Partition key isolation enforces data boundaries
Maintainability
Five-tier model pattern enables schema evolution
Service layer decouples business logic from storage
Consistent patterns across all entity services
Testability
Dependency injection via
get_container()Easy mocking with module-level globals
Clear separation enables unit testing without Cosmos
Performance
Partition key queries avoid cross-partition scans
Async wrapping prevents blocking FastAPI event loop
Minimal document conversion overhead
Files
- ATTRIBUTION.mdAdded by AutoGineer965 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md11.6 KiB
- assets/conftest_template.pyScript9.7 KiB
- assets/cosmos_client_template.pyScript6.2 KiB
- assets/service_template.pyScript9.2 KiB
- references/client-setup.md6.1 KiB
- references/error-handling.md10.3 KiB
- references/partitioning.md7.2 KiB
- references/service-layer.md8.2 KiB
- references/testing.md14.3 KiB
assets/conftest_template.py
"""
pytest Fixtures Template for Cosmos DB Testing
Production-ready test fixtures with:
- Mock Cosmos container
- Async operation mocking
- Sample document factories
- Integration test support
Usage:
Place in tests/conftest.py or import into test modules.
"""
from __future__ import annotations
import uuid
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any, Generator
from unittest.mock import MagicMock
import pytest
# -----------------------------------------------------------------------------
# Core Cosmos Fixtures
# -----------------------------------------------------------------------------
@pytest.fixture
def mock_cosmos_container() -> MagicMock:
"""
Mock Cosmos container with default behaviors.
Returns:
MagicMock configured for common Cosmos operations
"""
container = MagicMock()
# Default return values
container.read_item.return_value = None
container.upsert_item.side_effect = lambda doc: doc # Return the doc
container.delete_item.return_value = None
container.query_items.return_value = iter([])
return container
@pytest.fixture
def mock_cosmos(mock_cosmos_container: MagicMock, mocker) -> MagicMock:
"""
Patch get_container to return mock container.
Usage:
def test_something(mock_cosmos):
mock_cosmos.read_item.return_value = {"id": "123", ...}
result = await my_service.get_by_id("123", "workspace")
"""
mocker.patch("app.db.cosmos.get_container", return_value=mock_cosmos_container)
return mock_cosmos_container
@pytest.fixture
def mock_cosmos_unavailable(mocker) -> None:
"""
Simulate Cosmos being unavailable.
Usage:
def test_graceful_degradation(mock_cosmos_unavailable):
result = await my_service.list_items("workspace")
assert result == []
"""
mocker.patch("app.db.cosmos.get_container", return_value=None)
@pytest.fixture
def mock_cosmos_async(mock_cosmos_container: MagicMock, mocker) -> MagicMock:
"""
Mock the async wrapper functions (upsert_document, get_document, etc.).
This is useful when testing service layer directly.
"""
from azure.cosmos.exceptions import CosmosResourceNotFoundError
async def mock_upsert(doc: dict, partition_key: str) -> dict:
return mock_cosmos_container.upsert_item(doc)
async def mock_get(doc_id: str, partition_key: str) -> dict | None:
try:
return mock_cosmos_container.read_item(
item=doc_id, partition_key=partition_key
)
except CosmosResourceNotFoundError:
return None
async def mock_delete(doc_id: str, partition_key: str) -> bool:
try:
mock_cosmos_container.delete_item(
item=doc_id, partition_key=partition_key
)
return True
except CosmosResourceNotFoundError:
return False
async def mock_query(
doc_type: str,
partition_key: str | None = None,
extra_filter: str | None = None,
parameters: list | None = None,
) -> list[dict]:
return list(mock_cosmos_container.query_items())
mocker.patch("app.db.cosmos.upsert_document", side_effect=mock_upsert)
mocker.patch("app.db.cosmos.get_document", side_effect=mock_get)
mocker.patch("app.db.cosmos.delete_document", side_effect=mock_delete)
mocker.patch("app.db.cosmos.query_documents", side_effect=mock_query)
mocker.patch("app.db.cosmos.get_container", return_value=mock_cosmos_container)
return mock_cosmos_container
# -----------------------------------------------------------------------------
# Test Data Factories
# -----------------------------------------------------------------------------
@dataclass
class ProjectFactory:
"""
Factory for creating test project data.
Usage:
factory = ProjectFactory(name="Custom Name")
mock_cosmos.read_item.return_value = factory.to_doc()
"""
id: str = field(default_factory=lambda: str(uuid.uuid4()))
name: str = "Test Project"
description: str = "Test description"
slug: str = "test-project"
workspace_id: str = "ws-test"
author_id: str = "user-test"
visibility: str = "public"
tags: list[str] = field(default_factory=list)
created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
updated_at: datetime | None = None
def to_doc(self) -> dict[str, Any]:
"""Convert to Cosmos document format."""
return {
"id": self.id,
"name": self.name,
"description": self.description,
"slug": self.slug,
"workspaceId": self.workspace_id,
"authorId": self.author_id,
"visibility": self.visibility,
"tags": self.tags,
"createdAt": self.created_at.isoformat(),
"updatedAt": self.updated_at.isoformat() if self.updated_at else None,
"docType": "project",
}
@dataclass
class WorkspaceFactory:
"""Factory for creating test workspace data."""
id: str = field(default_factory=lambda: str(uuid.uuid4()))
name: str = "Test Workspace"
description: str = "Test workspace description"
slug: str = "test-workspace"
owner_id: str = "user-test"
visibility: str = "private"
created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
def to_doc(self) -> dict[str, Any]:
"""Convert to Cosmos document format."""
return {
"id": self.id,
"name": self.name,
"description": self.description,
"slug": self.slug,
"ownerId": self.owner_id,
"visibility": self.visibility,
"createdAt": self.created_at.isoformat(),
"docType": "workspace",
}
@dataclass
class UserFactory:
"""Factory for creating test user data."""
id: str = field(default_factory=lambda: str(uuid.uuid4()))
email: str = "[email protected]"
name: str = "Test User"
avatar_url: str | None = None
role: str = "author"
created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
def to_doc(self) -> dict[str, Any]:
"""Convert to Cosmos document format."""
return {
"id": self.id,
"email": self.email,
"name": self.name,
"avatarUrl": self.avatar_url,
"role": self.role,
"createdAt": self.created_at.isoformat(),
"docType": "user",
}
# -----------------------------------------------------------------------------
# Sample Document Fixtures
# -----------------------------------------------------------------------------
@pytest.fixture
def sample_project_doc() -> dict[str, Any]:
"""Sample project document as stored in Cosmos."""
return ProjectFactory().to_doc()
@pytest.fixture
def sample_workspace_doc() -> dict[str, Any]:
"""Sample workspace document as stored in Cosmos."""
return WorkspaceFactory().to_doc()
@pytest.fixture
def sample_user_doc() -> dict[str, Any]:
"""Sample user document as stored in Cosmos."""
return UserFactory().to_doc()
# -----------------------------------------------------------------------------
# Integration Test Fixtures
# -----------------------------------------------------------------------------
@pytest.fixture(scope="module")
def cosmos_container_integration():
"""
Real Cosmos container for integration tests.
Requires COSMOS_ENDPOINT environment variable.
Skipped if not configured.
"""
import os
if not os.getenv("COSMOS_ENDPOINT"):
pytest.skip("COSMOS_ENDPOINT not configured for integration tests")
from app.db.cosmos import get_container, reset_connection
reset_connection()
container = get_container()
if container is None:
pytest.skip("Could not connect to Cosmos DB")
yield container
reset_connection()
@pytest.fixture
def cleanup_test_docs(
cosmos_container_integration,
) -> Generator[list[tuple[str, str]], None, None]:
"""
Track and clean up test documents after each integration test.
Usage:
def test_create(cleanup_test_docs):
project = await service.create(...)
cleanup_test_docs.append((project.id, project.workspace_id))
# Document will be deleted after test
"""
created: list[tuple[str, str]] = []
yield created
# Cleanup
for doc_id, partition_key in created:
try:
cosmos_container_integration.delete_item(
item=doc_id, partition_key=partition_key
)
except Exception:
pass # Ignore cleanup errors
# -----------------------------------------------------------------------------
# Model Fixtures (customize for your models)
# -----------------------------------------------------------------------------
@pytest.fixture
def project_create_data():
"""
Sample ProjectCreate for testing.
TODO: Import and use your actual ProjectCreate model.
"""
# from app.models.project import ProjectCreate
# return ProjectCreate(
# name="New Project",
# description="Test description",
# workspace_id="ws-test",
# visibility="public",
# tags=["test"],
# )
return {
"name": "New Project",
"description": "Test description",
"workspace_id": "ws-test",
"visibility": "public",
"tags": ["test"],
}
@pytest.fixture
def project_update_data():
"""
Sample ProjectUpdate for testing.
TODO: Import and use your actual ProjectUpdate model.
"""
# from app.models.project import ProjectUpdate
# return ProjectUpdate(name="Updated Name")
return {"name": "Updated Name"}
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs an API key, Needs Python
Security
What our scanner noticed· Low risk
- Instructions that use the network
- Scripts that your agent may run
This skill includes scripts that your agent may run. Read them before you use it.
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Microsoft
- Publisher
- Microsoft (Official)
- Source
- microsoft/skills · .github/plugins/azure-sdk-python/skills/azure-cosmos-db-py · commit 0696600
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Microsoft.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download azure-cosmos-db-py.zip