Condividi tramite


Creare un'app console Rust con Azure Cosmos DB per MongoDB vCore

In questa guida viene creata un'applicazione console Rust per connettersi a un cluster vCore di Azure Cosmos DB per MongoDB. La guida illustra la configurazione dell'ambiente di sviluppo, usando il azure_identity crate di Azure SDK per Rust per l'autenticazione e la gestione dei documenti all'interno del database.

Prerequisiti

  • Un cluster esistente di Azure Cosmos DB per MongoDB (vCore).
  • Autenticazione di Microsoft Entra configurata per il cluster con il ruolo dbOwner assegnato alla tua identità.

  • Versione più recente di Python.

Configurare l'applicazione console

Creare quindi un nuovo progetto di applicazione console e importare le librerie necessarie per l'autenticazione nel cluster.

  1. Creare un nuovo progetto Rust usando cargo new.

    cargo new cosmos-mongodb-app
    cd cosmos-mongodb-app
    
  2. Aggiungere la azure_core cassa alle dipendenze.

    cargo add azure_core
    
  3. Aggiungi il azure_identity modulo per l'autenticazione.

    cargo add azure_identity
    
  4. Aggiungi il crate del mongodb driver al tuo cluster per interagire con esso.

    cargo add mongodb
    
  5. Per le operazioni asincrone, aggiungere anche i crate di supporto tokio, futures, e serde.

    cargo add tokio --features full
    cargo add futures
    cargo add serde --features derive
    

Connettersi al cluster

Ora, utilizza la libreria Azure.Identity per ottenere un TokenCredential da utilizzare per connetterti al cluster. Il driver Ufficiale di MongoDB ha un'interfaccia speciale che deve essere implementata per ottenere i token da Microsoft Entra per l'uso durante la connessione al cluster.

  1. Aprire il file main.rs e importare i crate e i moduli necessari.

    use azure_core::credentials::TokenCredential;
    use azure_identity::DefaultAzureCredential;
    use futures::{FutureExt, TryStreamExt};
    use mongodb::{
        Client,
        bson::doc,
        options::{
            AuthMechanism, ClientOptions, Credential,
            oidc::{self, IdpServerResponse},
        },
    };
    use serde::{Deserialize, Serialize};
    
  2. Creare la funzione asincrona principale con la gestione degli errori necessaria.

    #[tokio::main]
    async fn main() -> Result<(), Box<dyn std::error::Error>> {
    
        Ok(())
    }
    
  3. Creare una nuova istanza di struct azure_identity::DefaultAzureCredential.

    let credential = DefaultAzureCredential::new()?;
    
  4. Creare un callback delle credenziali per gestire le richieste di token dal client MongoDB.

    let azure_identity_token_credential = Credential::builder()
        .mechanism(AuthMechanism::MongoDbOidc)
        .oidc_callback(oidc::Callback::machine(move |_| {
            let azure_credential = credential.clone();
            async move {
                let access_token = azure_credential
                    .get_token(&["https://ossrdbms-aad.database.windows.net/.default"])
                    .await
                    .map_err(|e| {
                        mongodb::error::Error::custom(format!("Azure token error: {}", e))
                    })?;
                Ok(IdpServerResponse::builder()
                    .access_token(access_token.token.secret().to_owned())
                    .build())
            }
            .boxed()
        }))
        .build()
        .into();
    
  5. Definire un URI (Uniform Resource Indicator) del tuo cluster usando il nome, lo schema e l'endpoint globale.

    let cluster_name = "<azure-cosmos-db-mongodb-vcore-cluster-name>";
    
    let uri = format!(
        "mongodb+srv://{}.global.mongocluster.cosmos.azure.com/",
        cluster_name
    );
    
  6. Costruire un'istanza mongodb::ClientOptions utilizzando la configurazione delle migliori pratiche, il tuo URI e la funzione di callback delle credenziali.

    let mut client_options = ClientOptions::parse(uri).await?;
    
    client_options.connect_timeout = Some(std::time::Duration::from_secs(120));
    client_options.tls = Some(mongodb::options::Tls::Enabled(Default::default()));
    client_options.retry_writes = Some(true);
    
    client_options.credential = Some(azure_identity_token_credential);
    
  7. Creare una nuova istanza di mongodb::Client usando le impostazioni costruite.

    let client = Client::with_options(client_options)?;
    
    println!("Client created");
    

Eseguire operazioni comuni

Infine, usare la libreria ufficiale per eseguire attività comuni con database, raccolte e documenti. In questo caso si usano le stesse classi e metodi usati per interagire con MongoDB o DocumentDB per gestire le raccolte e gli elementi.

  1. Creare uno struct Rust per rappresentare i documenti Product con supporto per la serde serializzazione.

    #[derive(Serialize, Deserialize, Debug)]
    struct Product {
        _id: String,
        category: String,
        name: String,
        quantity: i32,
        price: f64,
        clearance: bool,
    }
    
  2. Ottieni un riferimento al tuo database per nome.

    let database = client.database("<database-name>");
    
    println!("Database pointer created");
    
  3. Ottieni un riferimento alla tua raccolta.

    let collection = database.collection::<Product>("<collection-name>");
    
    println!("Collection pointer created");
    
  4. Crea un documento usando collection.update_one e upsertalo nella raccolta.

    let document = Product {
        _id: "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb".to_string(),
        category: "gear-surf-surfboards".to_string(),
        name: "Yamba Surfboard".to_string(),
        quantity: 12,
        price: 850.00,
        clearance: false,
    };
    
    let response = collection
        .update_one(
            doc! { "_id": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb" },
            doc! { "$set": mongodb::bson::to_document(&document)? },
        )
        .upsert(true)
        .await?;
    
    println!("Documents upserted count:\t{}", response.modified_count);
    
  5. Leggere un documento specifico dalla raccolta usando collection.find_one e un filtro.

    let document = collection
        .find_one(doc! { "_id": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb" })
        .await?;
    
    println!("Read document _id:\t{:#?}", document.unwrap()._id);
    
  6. Eseguire una query per più documenti corrispondenti a un filtro usando collection.find.

    let filter = doc! { "category": "gear-surf-surfboards" };
    
    let mut cursor = collection.find(filter).await?;
    
    while let Some(document) = cursor.try_next().await? {
        println!("Found document:\t{:#?}", document);
    }