Build Azure Cosmos DB NoSQL services with Python/FastAPI following production-grade patterns. Use when implementing database client setup with dual auth (DefaultAzureCredential + emulator), service layer classes with CRUD operations, partition key strategies, parameterized queries, or TDD patterns for Cosmos. Triggers on phrases like "Cosmos DB", "NoSQL database", "document store", "add persistence", "database service layer", or "Python Cosmos SDK".
Add this skill
npx mdskills install sickn33/azure-cosmos-db-pyComprehensive production-grade patterns with strong security, clean architecture, and TDD guidance
1---2name: azure-cosmos-db-py3description: Build Azure Cosmos DB NoSQL services with Python/FastAPI following production-grade patterns. Use when implementing database client setup with dual auth (DefaultAzureCredential + emulator), service layer classes with CRUD operations, partition key strategies, parameterized queries, or TDD patterns for Cosmos. Triggers on phrases like "Cosmos DB", "NoSQL database", "document store", "add persistence", "database service layer", or "Python Cosmos SDK".4package: azure-cosmos5---67# Cosmos DB Service Implementation89Build production-grade Azure Cosmos DB NoSQL services following clean code, security best practices, and TDD principles.1011## Installation1213```bash14pip install azure-cosmos azure-identity15```1617## Environment Variables1819```bash20COSMOS_ENDPOINT=https://<account>.documents.azure.com:443/21COSMOS_DATABASE_NAME=<database-name>22COSMOS_CONTAINER_ID=<container-id>23# For emulator only (not production)24COSMOS_KEY=<emulator-key>25```2627## Authentication2829**DefaultAzureCredential (preferred)**:30```python31from azure.cosmos import CosmosClient32from azure.identity import DefaultAzureCredential3334client = CosmosClient(35 url=os.environ["COSMOS_ENDPOINT"],36 credential=DefaultAzureCredential()37)38```3940**Emulator (local development)**:41```python42from azure.cosmos import CosmosClient4344client = CosmosClient(45 url="https://localhost:8081",46 credential=os.environ["COSMOS_KEY"],47 connection_verify=False48)49```5051## Architecture Overview5253```54┌─────────────────────────────────────────────────────────────────┐55│ FastAPI Router │56│ - Auth dependencies (get_current_user, get_current_user_required)57│ - HTTP error responses (HTTPException) │58└──────────────────────────────┬──────────────────────────────────┘59 │60┌──────────────────────────────▼──────────────────────────────────┐61│ Service Layer │62│ - Business logic and validation │63│ - Document ↔ Model conversion │64│ - Graceful degradation when Cosmos unavailable │65└──────────────────────────────┬──────────────────────────────────┘66 │67┌──────────────────────────────▼──────────────────────────────────┐68│ Cosmos DB Client Module │69│ - Singleton container initialization │70│ - Dual auth: DefaultAzureCredential (Azure) / Key (emulator) │71│ - Async wrapper via run_in_threadpool │72└─────────────────────────────────────────────────────────────────┘73```7475## Quick Start7677### 1. Client Module Setup7879Create a singleton Cosmos client with dual authentication:8081```python82# db/cosmos.py83from azure.cosmos import CosmosClient84from azure.identity import DefaultAzureCredential85from starlette.concurrency import run_in_threadpool8687_cosmos_container = None8889def _is_emulator_endpoint(endpoint: str) -> bool:90 return "localhost" in endpoint or "127.0.0.1" in endpoint9192async def get_container():93 global _cosmos_container94 if _cosmos_container is None:95 if _is_emulator_endpoint(settings.cosmos_endpoint):96 client = CosmosClient(97 url=settings.cosmos_endpoint,98 credential=settings.cosmos_key,99 connection_verify=False100 )101 else:102 client = CosmosClient(103 url=settings.cosmos_endpoint,104 credential=DefaultAzureCredential()105 )106 db = client.get_database_client(settings.cosmos_database_name)107 _cosmos_container = db.get_container_client(settings.cosmos_container_id)108 return _cosmos_container109```110111**Full implementation**: See [references/client-setup.md](references/client-setup.md)112113### 2. Pydantic Model Hierarchy114115Use five-tier model pattern for clean separation:116117```python118class ProjectBase(BaseModel): # Shared fields119 name: str = Field(..., min_length=1, max_length=200)120121class ProjectCreate(ProjectBase): # Creation request122 workspace_id: str = Field(..., alias="workspaceId")123124class ProjectUpdate(BaseModel): # Partial updates (all optional)125 name: Optional[str] = Field(None, min_length=1)126127class Project(ProjectBase): # API response128 id: str129 created_at: datetime = Field(..., alias="createdAt")130131class ProjectInDB(Project): # Internal with docType132 doc_type: str = "project"133```134135### 3. Service Layer Pattern136137```python138class ProjectService:139 def _use_cosmos(self) -> bool:140 return get_container() is not None141142 async def get_by_id(self, project_id: str, workspace_id: str) -> Project | None:143 if not self._use_cosmos():144 return None145 doc = await get_document(project_id, partition_key=workspace_id)146 if doc is None:147 return None148 return self._doc_to_model(doc)149```150151**Full patterns**: See [references/service-layer.md](references/service-layer.md)152153## Core Principles154155### Security Requirements1561571. **RBAC Authentication**: Use `DefaultAzureCredential` in Azure — never store keys in code1582. **Emulator-Only Keys**: Hardcode the well-known emulator key only for local development1593. **Parameterized Queries**: Always use `@parameter` syntax — never string concatenation1604. **Partition Key Validation**: Validate partition key access matches user authorization161162### Clean Code Conventions1631641. **Single Responsibility**: Client module handles connection; services handle business logic1652. **Graceful Degradation**: Services return `None`/`[]` when Cosmos unavailable1663. **Consistent Naming**: `_doc_to_model()`, `_model_to_doc()`, `_use_cosmos()`1674. **Type Hints**: Full typing on all public methods1685. **CamelCase Aliases**: Use `Field(alias="camelCase")` for JSON serialization169170### TDD Requirements171172Write tests BEFORE implementation using these patterns:173174```python175@pytest.fixture176def mock_cosmos_container(mocker):177 container = mocker.MagicMock()178 mocker.patch("app.db.cosmos.get_container", return_value=container)179 return container180181@pytest.mark.asyncio182async def test_get_project_by_id_returns_project(mock_cosmos_container):183 # Arrange184 mock_cosmos_container.read_item.return_value = {"id": "123", "name": "Test"}185186 # Act187 result = await project_service.get_by_id("123", "workspace-1")188189 # Assert190 assert result.id == "123"191 assert result.name == "Test"192```193194**Full testing guide**: See [references/testing.md](references/testing.md)195196## Reference Files197198| File | When to Read |199|------|--------------|200| [references/client-setup.md](references/client-setup.md) | Setting up Cosmos client with dual auth, SSL config, singleton pattern |201| [references/service-layer.md](references/service-layer.md) | Implementing full service class with CRUD, conversions, graceful degradation |202| [references/testing.md](references/testing.md) | Writing pytest tests, mocking Cosmos, integration test setup |203| [references/partitioning.md](references/partitioning.md) | Choosing partition keys, cross-partition queries, move operations |204| [references/error-handling.md](references/error-handling.md) | Handling CosmosResourceNotFoundError, logging, HTTP error mapping |205206## Template Files207208| File | Purpose |209|------|---------|210| [assets/cosmos_client_template.py](assets/cosmos_client_template.py) | Ready-to-use client module |211| [assets/service_template.py](assets/service_template.py) | Service class skeleton |212| [assets/conftest_template.py](assets/conftest_template.py) | pytest fixtures for Cosmos mocking |213214## Quality Attributes (NFRs)215216### Reliability217- Graceful degradation when Cosmos unavailable218- Retry logic with exponential backoff for transient failures219- Connection pooling via singleton pattern220221### Security222- Zero secrets in code (RBAC via DefaultAzureCredential)223- Parameterized queries prevent injection224- Partition key isolation enforces data boundaries225226### Maintainability227- Five-tier model pattern enables schema evolution228- Service layer decouples business logic from storage229- Consistent patterns across all entity services230231### Testability232- Dependency injection via `get_container()`233- Easy mocking with module-level globals234- Clear separation enables unit testing without Cosmos235236### Performance237- Partition key queries avoid cross-partition scans238- Async wrapping prevents blocking FastAPI event loop239- Minimal document conversion overhead240
Full transparency — inspect the skill content before installing.