[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-7728b170-6dd1-4c89-bf16-934499abdd00":3,"$fZKJ8SI6TIkYAfN1Tr94D5U4WWVXiLTY5weX6mGhuZdA":42},{"id":4,"title":5,"description":6,"categoryId":7,"moduleId":8,"tags":9,"prompt":10,"icon":11,"source":12,"sourceUrl":13,"authorId":14,"authorName":15,"isPublic":16,"stars":17,"runs":18,"createdAt":19,"updatedAt":19,"module":20,"category":27,"packages":33},"7728b170-6dd1-4c89-bf16-934499abdd00","azure-cosmos-db-py","遵循清洁代码、安全最佳实践和TDD原则构建生产级别的Azure Cosmos DB NoSQL服务。","cat_coding_backend","mod_coding","sickn33,coding","---\nname: azure-cosmos-db-py\ndescription: \"Build production-grade Azure Cosmos DB NoSQL services following clean code, security best practices, and TDD principles.\"\nrisk: unknown\nsource: community\ndate_added: \"2026-02-27\"\n---\n\n# Cosmos DB Service Implementation\n\nBuild production-grade Azure Cosmos DB NoSQL services following clean code, security best practices, and TDD principles.\n\n## Installation\n\n```bash\npip install azure-cosmos azure-identity\n```\n\n## Environment Variables\n\n```bash\nCOSMOS_ENDPOINT=https:\u002F\u002F\u003Caccount>.documents.azure.com:443\u002F\nCOSMOS_DATABASE_NAME=\u003Cdatabase-name>\nCOSMOS_CONTAINER_ID=\u003Ccontainer-id>\n# For emulator only (not production)\nCOSMOS_KEY=\u003Cemulator-key>\n```\n\n## Authentication\n\n**DefaultAzureCredential (preferred)**:\n```python\nfrom azure.cosmos import CosmosClient\nfrom azure.identity import DefaultAzureCredential\n\nclient = CosmosClient(\n    url=os.environ[\"COSMOS_ENDPOINT\"],\n    credential=DefaultAzureCredential()\n)\n```\n\n**Emulator (local development)**:\n```python\nfrom azure.cosmos import CosmosClient\n\nclient = CosmosClient(\n    url=\"https:\u002F\u002Flocalhost:8081\",\n    credential=os.environ[\"COSMOS_KEY\"],\n    connection_verify=False\n)\n```\n\n## Architecture Overview\n\n```\n┌─────────────────────────────────────────────────────────────────┐\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) \u002F Key (emulator)   │\n│  - Async wrapper via run_in_threadpool                          │\n└─────────────────────────────────────────────────────────────────┘\n```\n\n## Quick Start\n\n### 1. Client Module Setup\n\nCreate a singleton Cosmos client with dual authentication:\n\n```python\n# db\u002Fcosmos.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) -> 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        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```\n\n**Full implementation**: See references\u002Fclient-setup.md\n\n### 2. Pydantic Model Hierarchy\n\nUse five-tier model pattern for clean separation:\n\n```python\nclass 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```\n\n### 3. Service Layer Pattern\n\n```python\nclass ProjectService:\n    def _use_cosmos(self) -> bool:\n        return get_container() is not None\n    \n    async def get_by_id(self, project_id: str, workspace_id: str) -> 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```\n\n**Full patterns**: See references\u002Fservice-layer.md\n\n## Core Principles\n\n### Security Requirements\n\n1. **RBAC Authentication**: Use `DefaultAzureCredential` in Azure — never store keys in code\n2. **Emulator-Only Keys**: Hardcode the well-known emulator key only for local development\n3. **Parameterized Queries**: Always use `@parameter` syntax — never string concatenation\n4. **Partition Key Validation**: Validate partition key access matches user authorization\n\n### Clean Code Conventions\n\n1. **Single Responsibility**: Client module handles connection; services handle business logic\n2. **Graceful Degradation**: Services return `None`\u002F`[]` when Cosmos unavailable\n3. **Consistent Naming**: `_doc_to_model()`, `_model_to_doc()`, `_use_cosmos()`\n4. **Type Hints**: Full typing on all public methods\n5. **CamelCase Aliases**: Use `Field(alias=\"camelCase\")` for JSON serialization\n\n### TDD Requirements\n\nWrite tests BEFORE implementation using these patterns:\n\n```python\n@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```\n\n**Full testing guide**: See references\u002Ftesting.md\n\n## Reference Files\n\n| File | When to Read |\n|------|--------------|\n| references\u002Fclient-setup.md | Setting up Cosmos client with dual auth, SSL config, singleton pattern |\n| references\u002Fservice-layer.md | Implementing full service class with CRUD, conversions, graceful degradation |\n| references\u002Ftesting.md | Writing pytest tests, mocking Cosmos, integration test setup |\n| references\u002Fpartitioning.md | Choosing partition keys, cross-partition queries, move operations |\n| references\u002Ferror-handling.md | Handling CosmosResourceNotFoundError, logging, HTTP error mapping |\n\n## Template Files\n\n| File | Purpose |\n|------|---------|\n| assets\u002Fcosmos_client_template.py | Ready-to-use client module |\n| assets\u002Fservice_template.py | Service class skeleton |\n| assets\u002Fconftest_template.py | pytest fixtures for Cosmos mocking |\n\n## Quality Attributes (NFRs)\n\n### Reliability\n- Graceful degradation when Cosmos unavailable\n- Retry logic with exponential backoff for transient failures\n- Connection pooling via singleton pattern\n\n### Security\n- Zero secrets in code (RBAC via DefaultAzureCredential)\n- Parameterized queries prevent injection\n- Partition key isolation enforces data boundaries\n\n### Maintainability\n- Five-tier model pattern enables schema evolution\n- Service layer decouples business logic from storage\n- Consistent patterns across all entity services\n\n### Testability\n- Dependency injection via `get_container()`\n- Easy mocking with module-level globals\n- Clear separation enables unit testing without Cosmos\n\n### Performance\n- Partition key queries avoid cross-partition scans\n- Async wrapping prevents blocking FastAPI event loop\n- Minimal document conversion overhead\n\n## When to Use\nThis skill is applicable to execute the workflow or actions described in the overview.\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.\n","","imported","https:\u002F\u002Fgithub.com\u002Fsickn33\u002Fantigravity-awesome-skills","user_system_seed","SkillOPIC",true,196,1757,"2026-05-16 13:06:04",{"id":8,"name":21,"slug":22,"icon":23,"description":24,"sort":25,"createdAt":26},"编程开发","coding","mdi-code-braces","代码生成、调试、审查，提升开发效率",2,"2026-05-16 12:53:40",{"id":7,"name":28,"slug":29,"icon":30,"description":31,"moduleId":8,"sort":25,"skillCount":32,"createdAt":26},"后端开发","backend","mdi-server","API、数据库、服务端架构",296,[34],{"id":35,"skillId":4,"version":36,"fileName":37,"fileSize":38,"filePath":39,"fileHash":40,"manifest":41,"createdAt":19},"b71ec6db-d0e3-4b8d-8127-d8982d1c581a","1.0.0","azure-cosmos-db-py.zip",3180,"uploads\u002Fskills\u002F7728b170-6dd1-4c89-bf16-934499abdd00\u002Fazure-cosmos-db-py.zip","9142fe4d766d65bf0d1967345a341aa1c3bc6587085349e48c19d130f196016f","[{\"path\":\"SKILL.md\",\"isDirectory\":false,\"size\":9220}]",{"code":43,"message":44,"data":45},200,"success",{"items":46,"stats":47,"page":50},[],{"averageRating":48,"totalRatings":48,"ratingCounts":49},0,[48,48,48,48,48],{"limit":51,"offset":48,"hasMore":52,"nextOffset":51,"ratedOnly":16},15,false]