option

azure-cosmos-db-py

microsoft/skills microsoft/skills

Développez des services NoSQL Azure Cosmos DB de niveau production avec Python/FastAPI, notamment la configuration du client avec double authentification, les opérations CRUD au niveau de la couche de service, les stratégies de clés de partition, les requêtes paramétrées et les modèles TDD.

...Développer tout
9
Heure mise à jour 12 septembre 2026

Mise en œuvre du service Cosmos DB

Développez des services NoSQL Azure Cosmos DB de niveau production en respectant les principes du « clean code », les meilleures pratiques en matière de sécurité et les principes du TDD.

Installation

pip install azure-cosmos azure-identity

Variables d’environnement

COSMOS_ENDPOINT=https://.documents.azure.com:443/  # Required for all auth methods
COSMOS_DATABASE_NAME=  # Required for all auth methods
COSMOS_CONTAINER_ID=  # Required for all auth methods
# For emulator only (not production)
COSMOS_KEY=  # Only required for key-based auth or emulator
AZURE_TOKEN_CREDENTIALS=prod # Required only if DefaultAzureCredential is used in production

Authentification et cycle de vie

🔑 Deux règles s'appliquent à tous les exemples de code ci-dessous :

  1. Privilégiez l'DefaultAzureCredential. Elle fonctionne en local (Azure CLI / VS Code / Developer CLI) et dans Azure (identité gérée, identité de charge de travail) sans modification du code. Évitez les chaînes de connexion, les identifiants de compte et les clés API : ils contournent l'audit et la rotation d'Entra.
    • Développement local : DefaultAzureCredential fonctionne tel quel.
    • Production : définissez AZURE_TOKEN_CREDENTIALS=prod (ou AZURE_TOKEN_CREDENTIALS=) pour limiter la chaîne d’informations d’identification aux identifiants sécurisés pour la production.
  2. Enveloppez chaque client dans un gestionnaire de contexte afin que les transports HTTP, les sockets et les caches de jetons soient libérés de manière déterministe :
    • Sync : with (...) as client:
    • Asynchrone : async with (...) as client: et async with DefaultAzureCredential() as credential: (d'après azure.identity.aio)

Les extraits de code peuvent simplifier cette configuration, mais le code de production doit toujours respecter ces deux règles.

DefaultAzureCredential (recommandé) :

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=
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)
    ...

Émulateur (développement local) :

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)
    ...

Présentation de l'architecture

┌─────────────────────────────────────────────────────────────────┐
│                         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                          │
└─────────────────────────────────────────────────────────────────┘

Démarrage rapide

1. Configuration du module client

Créez un client Cosmos singleton avec double authentification :

# 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_container

Implémentation complète : voir references/client-setup.md

2. Hiérarchie des modèles Pydantic

Utilisez le modèle à cinq couches pour une séparation claire :

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. Modèle de la couche de service

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)

Modèles complets : voir references/service-layer.md

Principes fondamentaux

Exigences de sécurité

  1. Authentification RBAC : utilisez DefaultAzureCredential Azure — ne stockez jamais de clés dans le code
  2. Clés réservées à l'émulateur : codez en dur la clé d'émulateur connue uniquement pour le développement local
  3. Requêtes paramétrées : utilisez toujours la @parameter la syntaxe — jamais la concaténation de chaînes
  4. Validation de la clé de partition : vérifiez que l’accès à la clé de partition correspond à l’autorisation de l’utilisateur

Conventions de code propre

  1. Responsabilité unique : le module client gère la connexion ; les services gèrent la logique métier
  2. Dégradation en douceur : les services renvoient None/[] lorsque Cosmos n’est pas disponible
  3. Nomenclature cohérente : _doc_to_model(), _model_to_doc(), _use_cosmos()
  4. Indicateurs de type : typage complet de toutes les méthodes publiques
  5. Alias CamelCase : utilisation Field(alias="camelCase") pour la sérialisation JSON

Exigences TDD

Écrivez les tests AVANT l'implémentation en suivant ces modèles :

@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"

Guide complet des tests : voir references/testing.md

Meilleures pratiques

  1. Cette compétence utilise async partout (azure.cosmos.aio) ; ne pas mélanger avec le client synchrone azure.cosmos. Conserver l'ensemble du chemin de requête FastAPI asynchrone — ne pas associer d'appels Cosmos synchrones à des gestionnaires asynchrones.
  2. Utilisez toujours des gestionnaires de contexte pour les clients et les identifiants asynchrones. Enveloppez le client dans async with CosmosClient(...) as client: (ou gérez son cycle de vie via la durée de vie FastAPI et fermez-le explicitement). Pour les DefaultAzureCredential de azure.identity.aio, utilisez également async with credential: afin que les jetons et les transports soient nettoyés.

Fichiers de référence

Fichier Quand le consulter
references/client-setup.md Configuration du client Cosmos avec double authentification, configuration SSL et modèle singleton
references/service-layer.md Implémentation d'une classe de service complète avec CRUD, conversions et dégradation gracieuse
references/testing.md Écriture de tests pytest, simulation de Cosmos, configuration des tests d'intégration
references/partitioning.md Choix des clés de partition, requêtes inter-partitions, opérations de déplacement
references/error-handling.md Gestion de l'erreur CosmosResourceNotFoundError, journalisation, mappage des erreurs HTTP

Fichiers modèles

Fichier Objectif
assets/cosmos_client_template.py Module client prêt à l'emploi
assets/service_template.py Squelette de classe de service
assets/conftest_template.py Fixtures pytest pour la simulation dans Cosmos

Attributs de qualité (NFR)

Fiabilité

  • Dégradation en douceur lorsque Cosmos n’est pas disponible
  • Logique de réessai avec délai d'attente exponentiel pour les défaillances transitoires
  • Pool de connexions via le modèle singleton

Sécurité

  • Aucun secret dans le code (RBAC via DefaultAzureCredential)
  • Les requêtes paramétrées empêchent les injections
  • L'isolation par clé de partition renforce les limites des données

Maintenabilité

  • Le modèle à cinq couches permet l’évolution du schéma
  • La couche de service dissocie la logique métier du stockage
  • Modèles cohérents pour tous les services d'entité

Testabilité

  • Injection de dépendances via get_container()
  • Simulation aisée grâce aux variables globales au niveau des modules
  • Une séparation claire permet de réaliser des tests unitaires sans Cosmos

Performances

  • Les requêtes par clé de partition évitent les balayages inter-partitions
  • L'encapsulation asynchrone empêche le blocage de la boucle d'événements FastAPI
  • Overhead minimal de conversion des documents
Voir sur GitHub
---
name: azure-cosmos-db-py
description: Build production-grade Azure Cosmos DB NoSQL services with Python/FastAPI, including client setup with dual authentication, service layer CRUD operations, partition key strategies, parameterized queries, and TDD patterns.
license: MIT
---

# 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://<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 production
```

## Authentication & Lifecycle

> **🔑 Two rules apply to every code sample below:**
>
> 1. **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: `DefaultAzureCredential` works as-is.
>    - Production: set `AZURE_TOKEN_CREDENTIALS=prod` (or `AZURE_TOKEN_CREDENTIALS=<specific_credential>`) to constrain the credential chain to production-safe credentials.
> 2. **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:` **and** `async with DefaultAzureCredential() as credential:` (from `azure.identity.aio`)
>
> Snippets may abbreviate this setup, but production code should always follow both rules.

**DefaultAzureCredential (preferred)**:
```python
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)**:
```python
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:

```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:
        # 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_container
```

**Full implementation**: See [references/client-setup.md](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](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](references/testing.md)

## Best Practices

1. **This skill uses async throughout (`azure.cosmos.aio`); do not mix with the sync `azure.cosmos` client.** Keep the whole FastAPI request path async — don't pair sync Cosmos calls with async handlers.
2. **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 async `DefaultAzureCredential` from `azure.identity.aio`, also use `async with credential:` so tokens and transports are cleaned up.

## Reference Files

| File | When to Read |
|------|--------------|
| [references/client-setup.md](references/client-setup.md) | Setting up Cosmos client with dual auth, SSL config, singleton pattern |
| [references/service-layer.md](references/service-layer.md) | Implementing full service class with CRUD, conversions, graceful degradation |
| [references/testing.md](references/testing.md) | Writing pytest tests, mocking Cosmos, integration test setup |
| [references/partitioning.md](references/partitioning.md) | Choosing partition keys, cross-partition queries, move operations |
| [references/error-handling.md](references/error-handling.md) | Handling CosmosResourceNotFoundError, logging, HTTP error mapping |

## Template Files

| File | Purpose |
|------|---------|
| [assets/cosmos_client_template.py](assets/cosmos_client_template.py) | Ready-to-use client module |
| [assets/service_template.py](assets/service_template.py) | Service class skeleton |
| [assets/conftest_template.py](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

Tous les fichiers

0 fichiers

Installer azure-cosmos-db-py

Téléchargez et décompressez les fichiers de compétences dans votre répertoire .claude/skills/.

Télécharger le ZIP

Clonez le dépôt et copiez les fichiers de compétence dans votre projet.

git clone https://github.com/microsoft/skills/tree/main/.github/plugins/azure-sdk-python/skills/azure-cosmos-db-py # Copy SKILL.md to your .claude/skills/ directory

Copier Copier
Configuration rapide: Copiez le dossier de la compétence dans .claude/skills/ Claude détectera automatiquement la compétence et l'utilisera

Compétences similaires

algorithmic-art
Heure mise à jour 27 août 2026
receiving-code-review
Heure mise à jour 3 septembre 2026
tech-debt-tracker
Heure mise à jour 29 août 2026
deprecation-and-migration
Heure mise à jour 3 septembre 2026
OR