Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Update a resource using a field mask

This guide shows you how to update a resource using a field mask, so that you can control which fields on the resource will be updated. The guide uses a secret from Secret Manager as a resource, but the concepts apply to other resources and services as well.

Prerequisites

To complete this tutorial, you need a Rust development environment with the following dependencies installed:

  • The Secret Manager client library
  • Tokio

To get set up, follow the steps in Setting up your development environment.

Install well known types

The google_cloud_wkt crate contains well known types for Google Cloud APIs. These types typically have custom JSON encoding, and may provide conversion functions to and from native or commonly used Rust types. google_cloud_wkt contains the field mask type, FieldMask, so you'll need to add the crate as a dependency:

cargo add google-cloud-wkt

FieldMask

A FieldMask represents a set of symbolic field paths. Field masks are used to specify a subset of fields that should be returned by a get operation or modified by an update operation.

A field mask in an update operation specifies which fields of the targeted resource should be updated. The API is required to change only the values of the fields specified in the mask and leave the others untouched. If a resource is passed in to describe the updated values, the API ignores the values of all fields not covered by the mask. If a field mask is not present on update, the operation applies to all fields (as if a field mask of all fields had been specified).

In order to reset a field to the default value, you must include the field in the mask and set the default value in the provided resource. Thus, in order to reset all fields of a resource, provide a default instance of the resource and set all fields in the mask, or don't provide a mask.

Update fields on a resource

First, initialize a Secret Manager client and create a secret:

    let client = SecretManagerService::builder().build().await?;

    let secret = client
        .create_secret()
        .set_parent(format!("projects/{project_id}"))
        .set_secret_id("your-secret")
        .set_secret(model::Secret::new().set_replication(
            model::Replication::new().set_automatic(model::replication::Automatic::new()),
        ))
        .send()
        .await?;
    println!("CREATE = {secret:?}");

If you examine the output from the create operation, you'll see that both the labels and annotations fields are empty.

The following code updates the labels and annotations fields:

    let tag = |mut labels: HashMap<_, _>, msg: &str| {
        labels.insert("updated".to_string(), msg.to_string());
        labels
    };

    let update = client
        .update_secret()
        .set_secret(
            model::Secret::new()
                .set_name(&secret.name)
                .set_etag(secret.etag)
                .set_labels(tag(secret.labels, "your-label"))
                .set_annotations(tag(secret.annotations, "your-annotations")),
        )
        .set_update_mask(
            google_cloud_wkt::FieldMask::default().set_paths(["annotations", "labels"]),
        )
        .send()
        .await?;
    println!("UPDATE = {update:?}");

The set_etag method lets you set an etag on the secret, which prevents overwriting concurrent updates.

Having set labels and annotations on the updated secret, you pass a field mask to set_update_mask specifying the field paths to be updated:

        .set_update_mask(
            google_cloud_wkt::FieldMask::default().set_paths(["annotations", "labels"]),
        )

In the output from the update operation, you can see that the fields have been updated:

labels: {"updated": "your-label"},
...
annotations: {"updated": "your-annotations"},

See below for the complete code.

What's next

In this guide, you updated a resource using a field mask. The sample code uses the Secret Manager API, but you can use field masks with other clients too. Try one of the other Cloud Client Libraries for Rust:


Update field: complete code

pub async fn update_field(project_id: &str) -> anyhow::Result<()> {
    use google_cloud_secretmanager_v1::client::SecretManagerService;
    use std::collections::HashMap;

    let client = SecretManagerService::builder().build().await?;

    let secret = client
        .create_secret()
        .set_parent(format!("projects/{project_id}"))
        .set_secret_id("your-secret")
        .set_secret(model::Secret::new().set_replication(
            model::Replication::new().set_automatic(model::replication::Automatic::new()),
        ))
        .send()
        .await?;
    println!("CREATE = {secret:?}");

    let tag = |mut labels: HashMap<_, _>, msg: &str| {
        labels.insert("updated".to_string(), msg.to_string());
        labels
    };

    let update = client
        .update_secret()
        .set_secret(
            model::Secret::new()
                .set_name(&secret.name)
                .set_etag(secret.etag)
                .set_labels(tag(secret.labels, "your-label"))
                .set_annotations(tag(secret.annotations, "your-annotations")),
        )
        .set_update_mask(
            google_cloud_wkt::FieldMask::default().set_paths(["annotations", "labels"]),
        )
        .send()
        .await?;
    println!("UPDATE = {update:?}");

    Ok(())
}