Cómo trabajar con operaciones de lista

Algunos servicios devuelven listas de elementos potencialmente grandes, como filas o descripciones de recursos. Para mantener bajo control el uso de CPU y memoria, los servicios devuelven estos recursos en pages: subconjuntos más pequeños de los elementos con un token de continuación para solicitar el siguiente subconjunto.

Iterar sobre los elementos por página puede ser tedioso. Las bibliotecas cliente proporcionan adaptadores para convertir las páginas en iteradores asíncronos. En esta guía, se muestra cómo trabajar con estos adaptadores.

Requisitos previos

En esta guía, se usa el servicio de Secret Manager para demostrar las operaciones de lista. Los conceptos que se incluyen en esta guía también se aplican a otros servicios.

Para seguir esta guía, deberás haber habilitado el servicio de Secret Manager, haber accedido y asegurarte de que tu cuenta tenga los permisos necesarios. Para obtener orientación sobre cómo cumplir con estos requisitos previos, sigue la guía de inicio rápido del servicio.

Para obtener instrucciones completas de configuración de las bibliotecas de Rust, consulta Configura tu entorno de desarrollo.

Dependencias

Agrega la biblioteca de Secret Manager a tu archivo Cargo.toml:

cargo add google-cloud-secretmanager-v1

Iteración de métodos de lista

Para ayudar a iterar los elementos en un método de lista, las APIs devuelven una implementación del atributo ItemPaginator. Introduce el rasgo en el alcance con una declaración use:

use google_cloud_gax::paginator::ItemPaginator as _;

Para iterar los elementos, usa el método by_item.

let mut list = client
    .list_secrets()
    .set_parent(format!("projects/{project_id}"))
    .by_item();
while let Some(secret) = list.next().await {
    let secret = secret?;
    println!("  secret={}", secret.name)
}

En casos excepcionales, es posible que las páginas contengan información adicional a la que necesites acceder o que debas establecer un punto de control de tu progreso en los procesos. Si es necesario, puedes iterar páginas completas en lugar de elementos individuales.

  1. Introduce Paginator en el alcance con una declaración use:

    use google_cloud_gax::paginator::Paginator as _;

  2. Itera en las páginas con by_page:

    let mut list = client
        .list_secrets()
        .set_parent(format!("projects/{project_id}"))
        .by_page();
    while let Some(page) = list.next().await {
        let page = page?;
        println!("  next_page_token={}", page.next_page_token);
        page.secrets
            .into_iter()
            .for_each(|secret| println!("    secret={}", secret.name));
    }

Trabajando con futures::Stream

Es posible que quieras usar estas APIs en el ecosistema de Rust más grande de transmisiones asíncronas, como tokio::Stream. Esto se puede lograr de la siguiente manera:

  1. Habilita la función unstable-streams en el cajón google_cloud_gax. El nombre de esta función sirve como aviso de que estas APIs son inestables. Solo debes usarlas si estás preparado para lidiar con cualquier interrupción que resulte de cambios incompatibles en el rasgo futures::Stream.

    cargo add google-cloud-gax --features unstable-stream
    
  2. En los siguientes ejemplos, también se usa el atributo futures::stream::StreamExt, que habilitas agregando el crate futures.

    cargo add futures
    
  3. Agrega las declaraciones use requeridas:

    use futures::stream::StreamExt;
    use google_cloud_gax::paginator::ItemPaginator as _;

  4. Usa la función into_stream para convertir ItemPaginator en un futures::Stream.

    let list = client
        .list_secrets()
        .set_parent(format!("projects/{project_id}"))
        .by_item()
        .into_stream();
    list.map(|secret| -> gax::Result<()> {
        println!("  secret={}", secret?.name);
        Ok(())
    })
    .fold(Ok(()), async |acc, result| -> gax::Result<()> {
        acc.and(result)
    })
    .await?;

Del mismo modo, puedes usar la función into_stream para convertir Paginator en un futures::Stream.

let list = client
    .list_secrets()
    .set_parent(format!("projects/{project_id}"))
    .by_page()
    .into_stream();
list.enumerate()
    .map(|(index, page)| -> gax::Result<()> {
        println!("page={}, next_page_token={}", index, page?.next_page_token);
        Ok(())
    })
    .fold(Ok(()), async |acc, result| -> gax::Result<()> {
        acc.and(result)
    })
    .await?;

Reanuda los métodos de lista configurando el token de la página siguiente

En algunos casos, como una operación de lista interrumpida, puedes configurar el token de la página siguiente para reanudar la paginación desde una página específica.

let page = client
    .list_secrets()
    .set_parent(format!("projects/{project_id}"))
    .send()
    .await;
let page = page?;
let mut next_page_token = page.next_page_token.clone();
page.secrets
    .into_iter()
    .for_each(|secret| println!("    secret={}", secret.name));

while !next_page_token.is_empty() {
    println!("  next_page_token={next_page_token}");

    let page = client
        .list_secrets()
        .set_parent(format!("projects/{project_id}"))
        .set_page_token(next_page_token)
        .send()
        .await;
    let page = page?;
    next_page_token = page.next_page_token.clone();

    page.secrets
        .into_iter()
        .for_each(|secret| println!("    secret={}", secret.name));
}

Cuándo usar los ayudantes del paginador

Las bibliotecas cliente de Google Cloud para Rust proporcionan un adaptador para convertir las RPC de lista, como se define en AIP-4233, en tipos que implementan ItemPaginator y Paginator si el método Google API List sigue el lineamiento de paginación definido por AIP-158. En resumen, este lineamiento requiere que cada llamada a un método List devuelva una página de elementos de recursos (por ejemplo, secretos) junto con un token que puedas pasar al método List para recuperar la página siguiente.

La mayoría de los servicios de Google Cloud siguen estos lineamientos. En los casos en los que no lo hagan, debes implementar tu propio adaptador para iterar los resultados.