{"slug":"azure-cosmos-db-py","title":"azure-cosmos-db-py","summary":"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 querie","platform":"GitHub Copilot","tags":[],"authorName":"Ciza","authorSlug":"ciza","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-08-12T21:05:06.519471Z","repo":{"url":"https://github.com/microsoft/skills","stars":3052,"forks":351,"license":"MIT","updatedAt":"2026-09-24T16:38:17Z"},"bodyHtml":"<hr>\n<h2>name: azure-cosmos-db-py\ndescription: 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\".\nlicense: MIT\nmetadata:\nauthor: Microsoft\nversion: \"1.0.0\"\npackage: azure-cosmos</h2>\n<h1>Cosmos DB Service Implementation</h1>\n<p>Build production-grade Azure Cosmos DB NoSQL services following clean code, security best practices, and TDD principles.</p>\n<h2>Installation</h2>\n<pre><code>pip install azure-cosmos azure-identity\n</code></pre>\n<h2>Environment Variables</h2>\n<pre><code>COSMOS_ENDPOINT=https://&lt;account&gt;.documents.azure.com:443/  # Required for all auth methods\nCOSMOS_DATABASE_NAME=&lt;database-name&gt;  # Required for all auth methods\nCOSMOS_CONTAINER_ID=&lt;container-id&gt;  # Required for all auth methods\n# For emulator only (not production)\nCOSMOS_KEY=&lt;emulator-key&gt;  # Only required for key-based auth or emulator\nAZURE_TOKEN_CREDENTIALS=prod # Required only if DefaultAzureCredential is used in production\n</code></pre>\n<h2>Authentication &amp; Lifecycle</h2>\n<blockquote>\n<p><strong>\uD83D\uDD11 Two rules apply to every code sample below:</strong></p>\n<ol>\n<li><strong>Prefer <code>DefaultAzureCredential</code>.</strong> 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.\n<ul>\n<li>Local dev: <code>DefaultAzureCredential</code> works as-is.</li>\n<li>Production: set <code>AZURE_TOKEN_CREDENTIALS=prod</code> (or <code>AZURE_TOKEN_CREDENTIALS=&lt;specific_credential&gt;</code>) to constrain the credential chain to production-safe credentials.</li>\n</ul>\n</li>\n<li><strong>Wrap every client in a context manager</strong> so HTTP transports, sockets, and token caches are released deterministically:\n<ul>\n<li>Sync: <code>with &lt;Client&gt;(...) as client:</code></li>\n<li>Async: <code>async with &lt;Client&gt;(...) as client:</code> <strong>and</strong> <code>async with DefaultAzureCredential() as credential:</code> (from <code>azure.identity.aio</code>)</li>\n</ul>\n</li>\n</ol>\n<p>Snippets may abbreviate this setup, but production code should always follow both rules.</p>\n</blockquote>\n<p><strong>DefaultAzureCredential (preferred)</strong>:</p>\n<pre><code>import os\nfrom azure.cosmos import CosmosClient\nfrom azure.identity import DefaultAzureCredential, ManagedIdentityCredential\n\n# Local dev: DefaultAzureCredential. Production: set AZURE_TOKEN_CREDENTIALS=prod or AZURE_TOKEN_CREDENTIALS=&lt;specific_credential&gt;\ncredential = DefaultAzureCredential(require_envvar=True)\n# Or use a specific credential directly in production:\n# See https://learn.microsoft.com/python/api/overview/azure/identity-readme?view=azure-python#credential-classes\n# credential = ManagedIdentityCredential()\n\nwith CosmosClient(\n    url=os.environ[\"COSMOS_ENDPOINT\"],\n    credential=credential\n) as client:\n    # Use client here (see following sections for operations)\n    ...\n</code></pre>\n<p><strong>Emulator (local development)</strong>:</p>\n<pre><code>from azure.cosmos import CosmosClient\n\nwith CosmosClient(\n    url=\"https://localhost:8081\",\n    credential=os.environ[\"COSMOS_KEY\"],\n    connection_verify=False\n) as client:\n    # Use client here (see following sections for operations)\n    ...\n</code></pre>\n<h2>Architecture Overview</h2>\n<pre><code>┌─────────────────────────────────────────────────────────────────┐\n│                         FastAPI Router                          │\n│  - Auth dependencies (get_current_user, get_current_user_required)\n│  - HTTP error responses (HTTPException)                         │\n└──────────────────────────────┬──────────────────────────────────┘\n                               │\n┌──────────────────────────────▼──────────────────────────────────┐\n│                        Service Layer                            │\n│  - Business logic and validation                                │\n│  - Document ↔ Model conversion                                  │\n│  - Graceful degradation when Cosmos unavailable                 │\n└──────────────────────────────┬──────────────────────────────────┘\n                               │\n┌──────────────────────────────▼──────────────────────────────────┐\n│                     Cosmos DB Client Module                     │\n│  - Singleton container initialization                           │\n│  - Dual auth: DefaultAzureCredential (Azure) / Key (emulator)   │\n│  - Async wrapper via run_in_threadpool                          │\n└─────────────────────────────────────────────────────────────────┘\n</code></pre>\n<h2>Quick Start</h2>\n<h3>1. Client Module Setup</h3>\n<p>Create a singleton Cosmos client with dual authentication:</p>\n<pre><code># db/cosmos.py\nfrom azure.cosmos import CosmosClient\nfrom azure.identity import DefaultAzureCredential\nfrom starlette.concurrency import run_in_threadpool\n\n_cosmos_container = None\n\ndef _is_emulator_endpoint(endpoint: str) -&gt; bool:\n    return \"localhost\" in endpoint or \"127.0.0.1\" in endpoint\n\nasync def get_container():\n    global _cosmos_container\n    if _cosmos_container is None:\n        # Singleton: client lives for the FastAPI app lifetime; close in a lifespan shutdown handler.\n        if _is_emulator_endpoint(settings.cosmos_endpoint):\n            client = CosmosClient(\n                url=settings.cosmos_endpoint,\n                credential=settings.cosmos_key,\n                connection_verify=False\n            )\n        else:\n            client = CosmosClient(\n                url=settings.cosmos_endpoint,\n                credential=DefaultAzureCredential()\n            )\n        db = client.get_database_client(settings.cosmos_database_name)\n        _cosmos_container = db.get_container_client(settings.cosmos_container_id)\n    return _cosmos_container\n</code></pre>\n<p><strong>Full implementation</strong>: See <a href=\"references/client-setup.md\">references/client-setup.md</a></p>\n<h3>2. Pydantic Model Hierarchy</h3>\n<p>Use five-tier model pattern for clean separation:</p>\n<pre><code>class ProjectBase(BaseModel):           # Shared fields\n    name: str = Field(..., min_length=1, max_length=200)\n\nclass ProjectCreate(ProjectBase):       # Creation request\n    workspace_id: str = Field(..., alias=\"workspaceId\")\n\nclass ProjectUpdate(BaseModel):         # Partial updates (all optional)\n    name: Optional[str] = Field(None, min_length=1)\n\nclass Project(ProjectBase):             # API response\n    id: str\n    created_at: datetime = Field(..., alias=\"createdAt\")\n\nclass ProjectInDB(Project):             # Internal with docType\n    doc_type: str = \"project\"\n</code></pre>\n<h3>3. Service Layer Pattern</h3>\n<pre><code>class ProjectService:\n    def _use_cosmos(self) -&gt; bool:\n        return get_container() is not None\n    \n    async def get_by_id(self, project_id: str, workspace_id: str) -&gt; Project | None:\n        if not self._use_cosmos():\n            return None\n        doc = await get_document(project_id, partition_key=workspace_id)\n        if doc is None:\n            return None\n        return self._doc_to_model(doc)\n</code></pre>\n<p><strong>Full patterns</strong>: See <a href=\"references/service-layer.md\">references/service-layer.md</a></p>\n<h2>Core Principles</h2>\n<h3>Security Requirements</h3>\n<ol>\n<li><strong>RBAC Authentication</strong>: Use <code>DefaultAzureCredential</code> in Azure — never store keys in code</li>\n<li><strong>Emulator-Only Keys</strong>: Hardcode the well-known emulator key only for local development</li>\n<li><strong>Parameterized Queries</strong>: Always use <code>@parameter</code> syntax — never string concatenation</li>\n<li><strong>Partition Key Validation</strong>: Validate partition key access matches user authorization</li>\n</ol>\n<h3>Clean Code Conventions</h3>\n<ol>\n<li><strong>Single Responsibility</strong>: Client module handles connection; services handle business logic</li>\n<li><strong>Graceful Degradation</strong>: Services return <code>None</code>/<code>[]</code> when Cosmos unavailable</li>\n<li><strong>Consistent Naming</strong>: <code>_doc_to_model()</code>, <code>_model_to_doc()</code>, <code>_use_cosmos()</code></li>\n<li><strong>Type Hints</strong>: Full typing on all public methods</li>\n<li><strong>CamelCase Aliases</strong>: Use <code>Field(alias=\"camelCase\")</code> for JSON serialization</li>\n</ol>\n<h3>TDD Requirements</h3>\n<p>Write tests BEFORE implementation using these patterns:</p>\n<pre><code>@pytest.fixture\ndef mock_cosmos_container(mocker):\n    container = mocker.MagicMock()\n    mocker.patch(\"app.db.cosmos.get_container\", return_value=container)\n    return container\n\n@pytest.mark.asyncio\nasync def test_get_project_by_id_returns_project(mock_cosmos_container):\n    # Arrange\n    mock_cosmos_container.read_item.return_value = {\"id\": \"123\", \"name\": \"Test\"}\n    \n    # Act\n    result = await project_service.get_by_id(\"123\", \"workspace-1\")\n    \n    # Assert\n    assert result.id == \"123\"\n    assert result.name == \"Test\"\n</code></pre>\n<p><strong>Full testing guide</strong>: See <a href=\"references/testing.md\">references/testing.md</a></p>\n<h2>Best Practices</h2>\n<ol>\n<li><strong>Pick sync OR async and stay consistent.</strong> Do not mix <code>azure.xxx</code> sync clients with <code>azure.xxx.aio</code> async clients in the same call path. Choose one mode per module.</li>\n<li><strong>Always use context managers for clients and async credentials.</strong> Wrap the client in <code>async with CosmosClient(...) as client:</code> (or manage its lifetime via FastAPI lifespan and close it explicitly). For async <code>DefaultAzureCredential</code> from <code>azure.identity.aio</code>, also use <code>async with credential:</code> so tokens and transports are cleaned up.</li>\n</ol>\n<h2>Reference Files</h2>\n<table>\n<thead>\n<tr>\n<th>File</th>\n<th>When to Read</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><a href=\"references/client-setup.md\">references/client-setup.md</a></td>\n<td>Setting up Cosmos client with dual auth, SSL config, singleton pattern</td>\n</tr>\n<tr>\n<td><a href=\"references/service-layer.md\">references/service-layer.md</a></td>\n<td>Implementing full service class with CRUD, conversions, graceful degradation</td>\n</tr>\n<tr>\n<td><a href=\"references/testing.md\">references/testing.md</a></td>\n<td>Writing pytest tests, mocking Cosmos, integration test setup</td>\n</tr>\n<tr>\n<td><a href=\"references/partitioning.md\">references/partitioning.md</a></td>\n<td>Choosing partition keys, cross-partition queries, move operations</td>\n</tr>\n<tr>\n<td><a href=\"references/error-handling.md\">references/error-handling.md</a></td>\n<td>Handling CosmosResourceNotFoundError, logging, HTTP error mapping</td>\n</tr>\n</tbody>\n</table>\n<h2>Template Files</h2>\n<table>\n<thead>\n<tr>\n<th>File</th>\n<th>Purpose</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><a href=\"assets/cosmos_client_template.py\">assets/cosmos_client_template.py</a></td>\n<td>Ready-to-use client module</td>\n</tr>\n<tr>\n<td><a href=\"assets/service_template.py\">assets/service_template.py</a></td>\n<td>Service class skeleton</td>\n</tr>\n<tr>\n<td><a href=\"assets/conftest_template.py\">assets/conftest_template.py</a></td>\n<td>pytest fixtures for Cosmos mocking</td>\n</tr>\n</tbody>\n</table>\n<h2>Quality Attributes (NFRs)</h2>\n<h3>Reliability</h3>\n<ul>\n<li>Graceful degradation when Cosmos unavailable</li>\n<li>Retry logic with exponential backoff for transient failures</li>\n<li>Connection pooling via singleton pattern</li>\n</ul>\n<h3>Security</h3>\n<ul>\n<li>Zero secrets in code (RBAC via DefaultAzureCredential)</li>\n<li>Parameterized queries prevent injection</li>\n<li>Partition key isolation enforces data boundaries</li>\n</ul>\n<h3>Maintainability</h3>\n<ul>\n<li>Five-tier model pattern enables schema evolution</li>\n<li>Service layer decouples business logic from storage</li>\n<li>Consistent patterns across all entity services</li>\n</ul>\n<h3>Testability</h3>\n<ul>\n<li>Dependency injection via <code>get_container()</code></li>\n<li>Easy mocking with module-level globals</li>\n<li>Clear separation enables unit testing without Cosmos</li>\n</ul>\n<h3>Performance</h3>\n<ul>\n<li>Partition key queries avoid cross-partition scans</li>\n<li>Async wrapping prevents blocking FastAPI event loop</li>\n<li>Minimal document conversion overhead</li>\n</ul>\n","files":[{"path":"assets/conftest_template.py","sizeBytes":9910,"isText":true},{"path":"assets/cosmos_client_template.py","sizeBytes":6339,"isText":true},{"path":"assets/service_template.py","sizeBytes":9410,"isText":true},{"path":"references/client-setup.md","sizeBytes":6238,"isText":true},{"path":"references/error-handling.md","sizeBytes":10525,"isText":true},{"path":"references/partitioning.md","sizeBytes":7330,"isText":true},{"path":"references/service-layer.md","sizeBytes":8431,"isText":true},{"path":"references/testing.md","sizeBytes":14648,"isText":true},{"path":"SKILL.md","sizeBytes":11894,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"notes-only","suspicious":0,"notes":1,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-08-12T21:49:57.797735Z","sha256":"17F8F03B861149E9DB0454B5E9B0C2725BDF3427BFF1664BA0C7B65520EFC2A6","sizeBytes":24964},"review":null,"source":{"repositoryUrl":"https://github.com/microsoft/skills","path":".github/plugins/azure-sdk-python/skills/azure-cosmos-db-py","license":"MIT","commit":"23d0dac5f83f268166a17f0bc7dc6c73dc348a33","subtreeSha":"016EB8D559A22DD9863DA0743AA6CE80C1B8A4AF3CF5D9399005FDD87C63B7EE","lastSyncedAt":"2026-09-25T06:48:53.330584Z"},"reviewedAt":"2026-08-12T21:52:21.879456Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/microsoft/skills/tree/main/.github/plugins/azure-sdk-python/skills/azure-cosmos-db-py"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install microsoft-skills@llmmart"},{"target":"git","command":"git clone https://github.com/microsoft/skills.git"}]}