Skip to content

Commit 71e51f7

Browse files
Use MetadataInterceptor for x-goog-api-client and other headers (#538)
* Update x-goog-api-client metadata header to use a interceptor. This change introduces a MetadataInterceptor to handle the addition of developer-token, login-customer-id, linked-customer-id, and x-goog-api-client modification, similar to the Python implementation. The ServiceLookup and generated factories are updated to use this new interceptor. Also added a test for the new interceptor. Co-authored-by: dorasun <10905385+dorasun@users.noreply.github.com> * Update x-goog-api-client metadata header to use a interceptor. This change introduces a MetadataInterceptor to handle the addition of developer-token, login-customer-id, linked-customer-id, and x-goog-api-client modification, similar to the Python implementation. The ServiceLookup and generated factories are updated to use this new interceptor. Also added a test for the new interceptor. Additionally, implemented gaada configuration support as requested. Co-authored-by: dorasun <10905385+dorasun@users.noreply.github.com> --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: dorasun <10905385+dorasun@users.noreply.github.com>
1 parent ae60711 commit 71e51f7

7 files changed

Lines changed: 210 additions & 15 deletions

File tree

codegen/templates/services.rb.erb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ module Google
99
def initialize(
1010
logging_interceptor:,
1111
error_interceptor:,
12+
metadata_interceptor:,
1213
credentials:,
1314
metadata:,
1415
endpoint:,
@@ -17,6 +18,7 @@ module Google
1718
@interceptors = [
1819
error_interceptor,
1920
logging_interceptor,
21+
metadata_interceptor
2022
].compact
2123
@credentials = credentials
2224
@metadata = metadata

lib/google/ads/google_ads/config.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class Config
3434
attr_accessor :login_customer_id
3535
attr_accessor :linked_customer_id
3636
attr_accessor :use_cloud_org_for_api_access
37+
attr_accessor :gaada
3738

3839
attr_accessor :log_level
3940
attr_accessor :log_target
@@ -59,6 +60,7 @@ def initialize(&block)
5960
@login_customer_id = nil
6061
@linked_customer_id = nil
6162
@use_cloud_org_for_api_access = false
63+
@gaada = nil
6264

6365
@log_level = nil
6466
@log_target = nil

lib/google/ads/google_ads/google_ads_client.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ def load_environment_config
114114
if @config.use_cloud_org_for_api_access.is_a?(String)
115115
@config.use_cloud_org_for_api_access = @config.use_cloud_org_for_api_access.downcase == "true"
116116
end
117+
@config.gaada = ENV.fetch("GOOGLE_ADS_GAADA", @config.gaada)
117118
end
118119

119120
# Return a service for the provided entity type. For example, passing
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Encoding: utf-8
2+
#
3+
# Copyright 2022 Google LLC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# https://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
# Interceptor to add metadata headers to requests.
18+
19+
require 'grpc/generic/interceptors'
20+
require 'google/protobuf'
21+
22+
module Google
23+
module Ads
24+
module GoogleAds
25+
module Interceptors
26+
class MetadataInterceptor < GRPC::ClientInterceptor
27+
def initialize(developer_token, login_customer_id, linked_customer_id, use_cloud_org_for_api_access, gaada)
28+
super()
29+
@developer_token = developer_token
30+
@login_customer_id = login_customer_id
31+
@linked_customer_id = linked_customer_id
32+
@use_cloud_org_for_api_access = use_cloud_org_for_api_access
33+
@gaada = gaada
34+
end
35+
36+
def request_response(request:, call:, method:, metadata: {})
37+
update_metadata(metadata)
38+
yield
39+
end
40+
41+
def server_streamer(request:, call:, method:, metadata: {})
42+
update_metadata(metadata)
43+
yield
44+
end
45+
46+
private
47+
48+
def update_metadata(metadata)
49+
if !@use_cloud_org_for_api_access
50+
metadata[:"developer-token"] = @developer_token
51+
end
52+
53+
if @login_customer_id
54+
metadata[:"login-customer-id"] = @login_customer_id.to_s
55+
end
56+
57+
if @linked_customer_id
58+
metadata[:"linked-customer-id"] = @linked_customer_id.to_s
59+
end
60+
61+
# The python library iterates over metadata and modifies x-goog-api-client
62+
# Here we can directly access it.
63+
if metadata.key?(:"x-goog-api-client")
64+
if @gaada
65+
metadata[:"x-goog-api-client"] += " gaada/#{@gaada}"
66+
end
67+
68+
# Check if "pb" is already in the header
69+
unless metadata[:"x-goog-api-client"].include?("pb")
70+
metadata[:"x-goog-api-client"] += " pb/#{Gem.loaded_specs["google-protobuf"].version}"
71+
end
72+
end
73+
end
74+
end
75+
end
76+
end
77+
end
78+
end

lib/google/ads/google_ads/service_lookup.rb

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require 'google/ads/google_ads/interceptors/logging_interceptor'
22
require 'google/ads/google_ads/interceptors/error_interceptor'
3+
require 'google/ads/google_ads/interceptors/metadata_interceptor'
34

45
module Google
56
module Ads
@@ -26,27 +27,36 @@ def call
2627
logging_interceptor = GoogleAds::Interceptors::LoggingInterceptor.new(logger)
2728
end
2829
error_interceptor = GoogleAds::Interceptors::ErrorInterceptor.new
30+
metadata_interceptor = GoogleAds::Interceptors::MetadataInterceptor.new(
31+
config.developer_token,
32+
config.login_customer_id,
33+
config.linked_customer_id,
34+
config.use_cloud_org_for_api_access,
35+
config.gaada
36+
)
2937

3038
version_alternates = {}
3139
Factories::VERSIONS.each do |v|
32-
version_alternates[v] = factory_at_version(v, error_interceptor, logging_interceptor)
40+
version_alternates[v] = factory_at_version(v, error_interceptor, logging_interceptor, metadata_interceptor)
3341
end
3442

3543
highest_factory = factory_at_version(
3644
Factories::HIGHEST_VERSION,
3745
error_interceptor,
3846
logging_interceptor,
47+
metadata_interceptor,
3948
)
4049

4150
VersionAlternate.new(highest_factory, version_alternates)
4251
end
4352

4453
private
4554

46-
def factory_at_version(version, error_interceptor, logging_interceptor)
55+
def factory_at_version(version, error_interceptor, logging_interceptor, metadata_interceptor)
4756
factory = Factories.at_version(version).services.new(**{
4857
logging_interceptor: logging_interceptor,
4958
error_interceptor: error_interceptor,
59+
metadata_interceptor: metadata_interceptor,
5060
deprecation: deprecator
5161
}.merge(gax_service_params))
5262

@@ -62,27 +72,15 @@ def gax_service_params
6272
end
6373

6474
def headers
65-
headers = {}
66-
67-
# If config.use_cloud_org_for_api_access is not True, add the developer
68-
# token to the request's metadata
69-
if !config.use_cloud_org_for_api_access
70-
headers[:"developer-token"] = config.developer_token
71-
end
72-
7375
if config.login_customer_id
7476
validate_customer_id(:login_customer_id)
75-
# header values must be strings
76-
headers[:"login-customer-id"] = config.login_customer_id.to_s
7777
end
7878

7979
if config.linked_customer_id
8080
validate_customer_id(:linked_customer_id)
81-
# header values must be strings
82-
headers[:"linked-customer-id"] = config.linked_customer_id.to_s
8381
end
8482

85-
headers
83+
{}
8684
end
8785

8886
def validate_customer_id(field)

test/test_config.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,21 @@ def test_initialize()
2727
client_id_value = 'client id'
2828
client_secret_value = 'client_secret'
2929
developer_token_value = 'developer_token'
30+
gaada_value = 'gaada_value'
3031

3132
config = Google::Ads::GoogleAds::Config.new do |c|
3233
c.refresh_token = refresh_token_value
3334
c.client_id = client_id_value
3435
c.client_secret = client_secret_value
3536
c.developer_token = developer_token_value
37+
c.gaada = gaada_value
3638
end
3739

3840
assert_equal(refresh_token_value, config.refresh_token)
3941
assert_equal(client_id_value, config.client_id)
4042
assert_equal(client_secret_value, config.client_secret)
4143
assert_equal(developer_token_value, config.developer_token)
44+
assert_equal(gaada_value, config.gaada)
4245
end
4346

4447
def test_configure()
@@ -48,18 +51,21 @@ def test_configure()
4851
client_id_value = 'abcd'
4952
client_secret_value = '!@#$'
5053
developer_token_value = '7x&Z'
54+
gaada_value = 'gaada_value'
5155

5256
config.configure do |c|
5357
c.refresh_token = refresh_token_value
5458
c.client_id = client_id_value
5559
c.client_secret = client_secret_value
5660
c.developer_token = developer_token_value
61+
c.gaada = gaada_value
5762
end
5863

5964
assert_equal(refresh_token_value, config.refresh_token)
6065
assert_equal(client_id_value, config.client_id)
6166
assert_equal(client_secret_value, config.client_secret)
6267
assert_equal(developer_token_value, config.developer_token)
68+
assert_equal(gaada_value, config.gaada)
6369
end
6470

6571
def test_use_cloud_org_for_api_access()

test/test_metadata_interceptor.rb

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#!/usr/bin/env ruby
2+
# Encoding: utf-8
3+
4+
require 'minitest/autorun'
5+
require 'google/ads/google_ads/interceptors/metadata_interceptor'
6+
require 'google/protobuf'
7+
8+
class TestMetadataInterceptor < Minitest::Test
9+
attr_reader :mi
10+
11+
def setup
12+
@mi = Google::Ads::GoogleAds::Interceptors::MetadataInterceptor.new(
13+
"dev_token",
14+
"login_id",
15+
"linked_id",
16+
false,
17+
nil
18+
)
19+
end
20+
21+
def test_adds_developer_token_if_not_cloud_org
22+
metadata = {}
23+
mi.request_response(
24+
request: nil,
25+
call: nil,
26+
method: nil,
27+
metadata: metadata
28+
) do
29+
end
30+
assert_equal "dev_token", metadata[:"developer-token"]
31+
end
32+
33+
def test_adds_login_and_linked_customer_id
34+
metadata = {}
35+
mi.request_response(
36+
request: nil,
37+
call: nil,
38+
method: nil,
39+
metadata: metadata
40+
) do
41+
end
42+
assert_equal "login_id", metadata[:"login-customer-id"]
43+
assert_equal "linked_id", metadata[:"linked-customer-id"]
44+
end
45+
46+
def test_appends_pb_version_to_x_goog_api_client
47+
metadata = { :"x-goog-api-client" => "gl-ruby/1.2.3" }
48+
mi.request_response(
49+
request: nil,
50+
call: nil,
51+
method: nil,
52+
metadata: metadata
53+
) do
54+
end
55+
assert_includes metadata[:"x-goog-api-client"], "pb/#{Gem.loaded_specs["google-protobuf"].version}"
56+
end
57+
58+
def test_does_not_duplicate_pb_version
59+
metadata = { :"x-goog-api-client" => "gl-ruby/1.2.3 pb/1.2.3" }
60+
mi.request_response(
61+
request: nil,
62+
call: nil,
63+
method: nil,
64+
metadata: metadata
65+
) do
66+
end
67+
assert_equal "gl-ruby/1.2.3 pb/1.2.3", metadata[:"x-goog-api-client"]
68+
end
69+
70+
def test_skips_developer_token_if_cloud_org
71+
mi_cloud = Google::Ads::GoogleAds::Interceptors::MetadataInterceptor.new(
72+
"dev_token",
73+
"login_id",
74+
"linked_id",
75+
true,
76+
nil
77+
)
78+
metadata = {}
79+
mi_cloud.request_response(
80+
request: nil,
81+
call: nil,
82+
method: nil,
83+
metadata: metadata
84+
) do
85+
end
86+
assert_nil metadata[:"developer-token"]
87+
end
88+
89+
def test_appends_gaada_to_x_goog_api_client
90+
mi_gaada = Google::Ads::GoogleAds::Interceptors::MetadataInterceptor.new(
91+
"dev_token",
92+
"login_id",
93+
"linked_id",
94+
false,
95+
"1.2.3"
96+
)
97+
metadata = { :"x-goog-api-client" => "gl-ruby/1.2.3" }
98+
mi_gaada.request_response(
99+
request: nil,
100+
call: nil,
101+
method: nil,
102+
metadata: metadata
103+
) do
104+
end
105+
assert_includes metadata[:"x-goog-api-client"], "gaada/1.2.3"
106+
assert_includes metadata[:"x-goog-api-client"], "pb/#{Gem.loaded_specs["google-protobuf"].version}"
107+
end
108+
end

0 commit comments

Comments
 (0)