googleads-rs

Crates.iogoogleads-rs
lib.rsgoogleads-rs
version0.8.0
sourcesrc
created_at2023-08-13 12:21:44.428523
updated_at2024-08-10 15:52:35.370097
descriptionA gRPC client library for Google Ads API, generated automatically from the API definition files.
homepage
repositoryhttps://github.com/mhuang74/googleads-rs
max_upload_size
id943286
size3,947,092
Michael S. Huang (mhuang74)

documentation

README

googleads-rs

Maintenance CI crates-io api-docs

Current Version 0.8.0 uses Google Ads API v17.1

A gRPC client library for Google Ads API, generated automatically from the API definition files.

I use it for my mcc-gaql command line tool to run Google Ads Query Language queries across large number of MCC-linked accounts.

There may be more elegant ways to pull query results from GoogleAdsRow in a reflection-like manner. I couldn't figure it out. So I hand-crafted a GoogleAdsRow.get(path: &str) accessor method for fields which I need.

Example

    let client: GoogleAdsServiceClient<InterceptedService<Channel, GoogleAdsAPIAccess>> =
        GoogleAdsServiceClient::with_interceptor(api_context.channel.clone(), api_context);

    let result: Result<Response<Streaming<SearchGoogleAdsStreamResponse>>, Status> = client
        .search_stream(SearchGoogleAdsStreamRequest {
            customer_id: customer_id.clone(),
            query,
            summary_row_setting: 0,
        })
        .await;

    match result {
        Ok(response) => {
            let mut stream = response.into_inner();

            let mut columns: Vec<Vec<String>> = Vec::new();
            let mut headers: Option<Vec<String>> = None;

            while let Some(item) = stream.next().await {
                match item {
                    Ok(stream_response) => {
                        let field_mask = stream_response.field_mask.unwrap();
                        if headers.is_none() {
                            headers = Some(field_mask.paths.clone());
                        }
                        for r in stream_response.results {
                            let row: GoogleAdsRow = r;

                            // go through all columns specified in query, pull out string value, and insert into columns
                            for i in 0..headers.as_ref().unwrap().len() {
                                let path = &headers.as_ref().unwrap()[i];
                                let string_val: String = row.get(path).trim_matches('"').to_string();
                                match columns.get_mut(i) {
                                    Some(v) => {
                                        v.push(string_val);
                                    }
                                    None => {
                                        let v: Vec<String> = vec![string_val];
                                        columns.insert(i, v);
                                    }
                                }
                            }
                        }
                    }
                    Err(status) => {
                        bail!(
                            "GoogleAdsClient streaming error. Account: {customer_id}, Message: {}, Details: {}",
                            status.message(),
                            String::from_utf8_lossy(status.details()).into_owned()
                        );
                    }
                }
            }
        }
    }

API Upgrade

Run update.sh to update the library for a new Google Ads API version:

  • Download latest proto files for new Google Ads API version
  • Replace references to old api version in build.rs, lib.rs, and README.md
./utils/update.sh v17

Build process

  • build.rs dynamically scans for available proto files, filters them, and feeds them to tonic to generate protos.rs (following strategy by aquarhead)
  • lib.rs includes protos.rs
  • lib.rs also includes hand-crafted get() function
    pub fn get(&self, field_name: &str) -> String {
        match field_name {
            "ad_group_criterion.criterion_id" => format!("{}", self.ad_group_criterion.as_ref().unwrap().criterion_id),
            "ad_group_criterion.status" => format!("{}", self.ad_group_criterion.as_ref().unwrap().status()),
            <snip>
        }
    }

Credits

Commit count: 138

cargo fmt