#grpc-client #grpc #api-client #query-language #googleads #gapi

googleads-rs

Google Ads API 的 gRPC 客户端库,自动从 API 定义文件生成

5 个版本 (3 个破坏性更新)

新功能 0.8.0 2024年8月10日
0.7.0 2024年4月14日
0.6.0 2023年11月25日
0.5.1 2023年9月12日
0.5.0 2023年8月13日

#31 in #grpc-client

Download history 154/week @ 2024-04-13 3/week @ 2024-04-20 5/week @ 2024-05-18 1/week @ 2024-05-25

每月下载量 247

MIT 许可证

585KB
463 代码行

googleads-rs

Maintenance CI crates-io api-docs

当前版本 0.8.0 使用 Google Ads API v17.1

Google Ads API 的 gRPC 客户端库,自动从 API 定义文件生成。

我使用它来运行 Google Ads Query Language 查询,跨越大量 MCC 账户。

可能有更优雅的方法从 GoogleAdsRow 以反射方式拉取查询结果。我没能找到。所以我手动制作了一个 GoogleAdsRow.get(path: &str) 访问器方法来获取我需要的字段。

示例

    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 升级

运行 update.sh 来更新库以支持新的 Google Ads API 版本

  • 下载新 Google Ads API 版本的最新的 proto 文件
  • 在 build.rs、lib.rs 和 README.md 中替换对旧 API 版本的引用
./utils/update.sh v17

构建过程

  • build.rs 动态扫描可用的 proto 文件,过滤它们,并将它们传递给 tonic 以生成 protos.rs (遵循 aquarhead 的策略)
  • lib.rs 包含 protos.rs
  • lib.rs 还包含手动编写的 get() 函数
    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>
        }
    }

致谢

  • 最初是从 gkkachi 的 gapi-grpc-rs 分支出来的,它使用 Python 生成 protos.rs
  • 删除了 Python 并迁移到自定义的 build.rs,根据 aquarhead 的建议

依赖关系

~13–24MB
~437K SLoC