--- name: azure-cosmos-db-py description: "Build production-grade Azure Cosmos DB NoSQL services following clean code, security best practices, and TDD principles." risk: unknown source: community date_added: "2026-02-27" --- # Cosmos DB Service Implementation Build production-grade Azure Cosmos DB NoSQL services following clean code, security best practices, and TDD principles. ## Installation ```bash pip install azure-cosmos azure-identity ``` ## Environment Variables ```bash COSMOS_ENDPOINT=https://.documents.azure.com:443/ COSMOS_DATABASE_NAME= COSMOS_CONTAINER_ID= # For emulator only (not production) COSMOS_KEY= ``` ## Authentication **DefaultAzureCredential (preferred)**: ```python from azure.cosmos import CosmosClient from azure.identity import DefaultAzureCredential client = CosmosClient( url=os.environ["COSMOS_ENDPOINT"], credential=DefaultAzureCredential() ) ``` **Emulator (local development)**: ```python from azure.cosmos import CosmosClient client = CosmosClient( url="https://localhost:8081", credential=os.environ["COSMOS_KEY"], connection_verify=False ) ``` ## 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: ```python # 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: 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_container ``` **Full implementation**: See references/client-setup.md ### 2. Pydantic Model Hierarchy Use five-tier model pattern for clean separation: ```python 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 ```python 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 1. **RBAC Authentication**: Use `DefaultAzureCredential` in Azure — never store keys in code 2. **Emulator-Only Keys**: Hardcode the well-known emulator key only for local development 3. **Parameterized Queries**: Always use `@parameter` syntax — never string concatenation 4. **Partition Key Validation**: Validate partition key access matches user authorization ### Clean Code Conventions 1. **Single Responsibility**: Client module handles connection; services handle business logic 2. **Graceful Degradation**: Services return `None`/`[]` when Cosmos unavailable 3. **Consistent Naming**: `_doc_to_model()`, `_model_to_doc()`, `_use_cosmos()` 4. **Type Hints**: Full typing on all public methods 5. **CamelCase Aliases**: Use `Field(alias="camelCase")` for JSON serialization ### TDD Requirements Write tests BEFORE implementation using these patterns: ```python @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 ## 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 ## When to Use This skill is applicable to execute the workflow or actions described in the overview. ## Limitations - Use this skill only when the task clearly matches the scope described above. - Do not treat the output as a substitute for environment-specific validation, testing, or expert review. - Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.