Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ Use this skill when:

- An app needs to store or query documents in Cosmos DB from Rust
- You need CRUD operations on items with partition keys
- You need multi-region routing with `RoutingStrategy`
- You need key-based auth as an alternative to Entra ID

> **IMPORTANT:** Only use the official `azure_data_cosmos` crate published by the [azure-sdk](https://crates.io/users/azure-sdk) crates.io user. Do NOT use the unofficial `azure_cosmos` or `azure_sdk_for_rust` community crates. Official crates use underscores in names and none have version 0.21.0.
Expand All @@ -40,9 +39,7 @@ COSMOS_ENDPOINT=https://<account>.documents.azure.com/ # Required for all operat

```rust
use azure_identity::DeveloperToolsCredential;
use azure_data_cosmos::{
CosmosClient, CosmosAccountReference, CosmosAccountEndpoint, RoutingStrategy,
};
use azure_data_cosmos::{CosmosClient, CosmosAccountReference, CosmosAccountEndpoint};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
Expand All @@ -52,9 +49,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let endpoint: CosmosAccountEndpoint = "https://<account>.documents.azure.com/"
.parse()?;
let account = CosmosAccountReference::with_credential(endpoint, credential);
let client = CosmosClient::builder()
.build(account, RoutingStrategy::ProximityTo("East US".into()))
.await?;
let client = CosmosClient::builder().build(account).await?;
Ok(())
}
```
Expand All @@ -63,9 +58,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {

| Client | Purpose | Access |
| ----------------- | ------------------------- | --------------------------------------- |
| `CosmosClient` | Account-level operations | `CosmosClient::builder().build()` |
| `CosmosClient` | Account-level operations | `CosmosClient::builder().build(account).await?` |
| `DatabaseClient` | Database operations | `client.database_client("db")` |
| `ContainerClient` | Container/item operations | `database.container_client("c").await?` |
| `ContainerClient` | Container/item operations | `database.container_client("c").await` |

## Core Workflow

Expand All @@ -84,7 +79,7 @@ async fn crud(client: CosmosClient) -> Result<(), Box<dyn std::error::Error>> {
let container = client
.database_client("myDatabase")
.container_client("myContainer")
.await?;
.await;

let item = Item {
id: "1".into(),
Expand Down Expand Up @@ -131,8 +126,7 @@ For Entra ID auth, assign one of these built-in Cosmos DB roles:
1. **Use `DeveloperToolsCredential`** for local dev, **`ManagedIdentityCredential`** for production — the Rust SDK does not have `DefaultAzureCredential`
2. **Never hardcode credentials** — use environment variables or managed identity
3. **Reuse `CosmosClient`** — clients are thread-safe; create once, share across tasks
4. **Use `RoutingStrategy::ProximityTo`** — route to the nearest region for lowest latency
5. **Always specify partition key** for item operations — Cosmos DB requires it for all CRUD
4. **Always specify partition key** for item operations — Cosmos DB requires it for all CRUD

## Reference Links

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,17 @@ AZURE_STORAGE_ENDPOINT=https://<account>.blob.core.windows.net/ # Required for a
## Authentication

```rust
use azure_core::http::Url;
use azure_identity::DeveloperToolsCredential;
use azure_storage_blob::BlobClient;
use azure_storage_blob::BlobServiceClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Local dev: DeveloperToolsCredential. Production: use ManagedIdentityCredential.
let credential = DeveloperToolsCredential::new(None)?;
let blob_client = BlobClient::new(
"https://<account>.blob.core.windows.net/",
"container-name",
"blob-name",
Some(credential),
None,
)?;
let service_url = Url::parse("https://<account>.blob.core.windows.net/")?;
let service_client = BlobServiceClient::new(service_url, Some(credential), None)?;
let blob_client = service_client.blob_client("container-name", "blob-name");
Ok(())
}
```
Expand All @@ -71,20 +68,17 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {

```rust
use azure_core::http::RequestContent;
use azure_core::http::Url;
use azure_identity::DeveloperToolsCredential;
use azure_storage_blob::BlobClient;
use azure_storage_blob::BlobServiceClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Local dev: DeveloperToolsCredential. Production: use ManagedIdentityCredential.
let credential = DeveloperToolsCredential::new(None)?;
let blob_client = BlobClient::new(
"https://<account>.blob.core.windows.net/",
"container-name",
"blob-name",
Some(credential),
None,
)?;
let service_url = Url::parse("https://<account>.blob.core.windows.net/")?;
let service_client = BlobServiceClient::new(service_url, Some(credential), None)?;
let blob_client = service_client.blob_client("container-name", "blob-name");

let data = b"hello world";
blob_client
Expand All @@ -102,7 +96,7 @@ let props = blob_client.get_properties(None).await?;

// Download blob content
let response = blob_client.download(None).await?;
let content = response.into_body().collect_bytes().await?;
let content = String::from_utf8(response.body.collect().await?.into())?;
```

### Delete Blob
Expand All @@ -114,17 +108,15 @@ blob_client.delete(None).await?;
### Container Operations

```rust
use azure_core::http::Url;
use azure_identity::DeveloperToolsCredential;
use azure_storage_blob::BlobContainerClient;
use azure_storage_blob::BlobServiceClient;
use futures::TryStreamExt as _;

let credential = DeveloperToolsCredential::new(None)?;
let container_client = BlobContainerClient::new(
"https://<account>.blob.core.windows.net/",
"container-name",
Some(credential),
None,
)?;
let service_url = Url::parse("https://<account>.blob.core.windows.net/")?;
let service_client = BlobServiceClient::new(service_url, Some(credential), None)?;
let container_client = service_client.blob_container_client("container-name");

// Create container
container_client.create(None).await?;
Expand All @@ -148,7 +140,7 @@ let result = blob_client.download(None).await;

match result {
Ok(response) => {
let content = response.into_body().collect_bytes().await?;
let content: Vec<u8> = response.body.collect().await?.into();
println!("Downloaded {} bytes", content.len());
}
Err(error) => {
Expand Down
138 changes: 138 additions & 0 deletions .github/skills/azure-cosmos-rust/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
---
name: azure-cosmos-rust
description: |
Azure Cosmos DB library for Rust (NoSQL API). Document CRUD, containers, and globally distributed data.
Triggers: "cosmos db rust", "CosmosClient rust", "document crud rust", "NoSQL rust", "partition key rust".
license: MIT
metadata:
author: Microsoft
package: azure_data_cosmos
---

# Azure Cosmos DB library for Rust

Client library for Azure Cosmos DB NoSQL API — document CRUD, containers, and globally distributed data.

Use this skill when:

- An app needs to store or query documents in Cosmos DB from Rust
- You need CRUD operations on items with partition keys
- You need key-based auth as an alternative to Entra ID

> **IMPORTANT:** Only use the official `azure_data_cosmos` crate published by the [azure-sdk](https://crates.io/users/azure-sdk) crates.io user. Do NOT use the unofficial `azure_cosmos` or `azure_sdk_for_rust` community crates. Official crates use underscores in names and none have version 0.21.0.

## Installation

```sh
cargo add azure_data_cosmos azure_identity tokio
```

> **Do not** add `azure_core` directly to `Cargo.toml`. It is re-exported by `azure_data_cosmos`.

## Environment Variables

```bash
COSMOS_ENDPOINT=https://<account>.documents.azure.com/ # Required for all operations
```

## Authentication

```rust
use azure_identity::DeveloperToolsCredential;
use azure_data_cosmos::{CosmosClient, CosmosAccountReference, CosmosAccountEndpoint};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Local dev: DeveloperToolsCredential. Production: use ManagedIdentityCredential.
let credential: std::sync::Arc<dyn azure_core::credentials::TokenCredential> =
DeveloperToolsCredential::new(None)?;
let endpoint: CosmosAccountEndpoint = "https://<account>.documents.azure.com/"
.parse()?;
let account = CosmosAccountReference::with_credential(endpoint, credential);
let client = CosmosClient::builder().build(account).await?;
Ok(())
}
```

## Client Hierarchy

| Client | Purpose | Access |
| ----------------- | ------------------------- | ----------------------------------------------- |
| `CosmosClient` | Account-level operations | `CosmosClient::builder().build(account).await?` |
| `DatabaseClient` | Database operations | `client.database_client("db")` |
| `ContainerClient` | Container/item operations | `database.container_client("c").await` |

## Core Workflow

```rust
use serde::{Serialize, Deserialize};
use azure_data_cosmos::CosmosClient;

#[derive(Serialize, Deserialize)]
struct Item {
pub id: String,
pub partition_key: String,
pub value: String,
}

async fn crud(client: CosmosClient) -> Result<(), Box<dyn std::error::Error>> {
let container = client
.database_client("myDatabase")
.container_client("myContainer")
.await;

let item = Item {
id: "1".into(),
partition_key: "pk1".into(),
value: "hello".into(),
};

// Create
container.create_item("pk1", item, None).await?;

// Read
let resp = container.read_item("pk1", "1", None).await?;
let mut item: Item = resp.into_model()?;

// Update
item.value = "updated".into();
container.replace_item("pk1", "1", item, None).await?;

// Delete
container.delete_item("pk1", "1", None).await?;
Ok(())
}
```

## Key Auth (Optional)

Enable account key authentication with the feature flag:

```sh
cargo add azure_data_cosmos --features key_auth
```

## RBAC Roles

For Entra ID auth, assign one of these built-in Cosmos DB roles:

| Role | Access |
| ------------------------------------- | ---------- |
| `Cosmos DB Built-in Data Reader` | Read-only |
| `Cosmos DB Built-in Data Contributor` | Read/write |

## Best Practices

1. **Use `DeveloperToolsCredential` for local development and `ManagedIdentityCredential` for production.** The Rust SDK does not support `DefaultAzureCredential`, so explicitly use the appropriate credential in each environment.
2. **Always specify partition key for item operations.** Cosmos DB requires the partition key for all CRUD operations; include it in every `create_item()`, `read_item()`, `replace_item()`, and `delete_item()` call.
3. **Assign appropriate RBAC roles for Entra ID auth.** For production authentication using Entra ID, ensure the identity has the necessary RBAC role assigned (e.g., "Cosmos DB Built-in Data Contributor" for read/write).
4. **Always verify package versions using crates.io.** Before using a package, check its version on [crates.io](https://crates.io/) to ensure you are using a stable and supported release.
5. **Never hardcode credentials** — use environment variables or managed identity
6. **Reuse `CosmosClient`** — clients are thread-safe; create once, share across tasks

## Reference Links

| Resource | Link |
| ------------- | ------------------------------------------ |
| API Reference | https://docs.rs/azure_data_cosmos |
| crates.io | https://crates.io/crates/azure_data_cosmos |
Loading
Loading