Since the Google Ads API uses Protobuf as its default payload format, it's important to understand a few Protobuf conventions and types when working with the API.
Optional fields
Many fields in the Google Ads API are marked as optional
. This lets you
distinguish between cases where the field has an empty value, versus the server
did not send back a value for the field. These fields behave like regular
fields, except they also provide additional methods to clear the field and to
check if the field is set.
For example, the Name
field of the Campaign
object is marked as optional.
So you can use the following methods to work with this field.
// Get the name.
string
name
=
campaign
.
Name
;
// Set the name.
campaign
.
Name
=
name
;
// Check if the campaign object has the name field set.
bool
hasName
=
campaign
.
HasName
();
// Clear the name field. Use this method to exclude Name field from
// being sent to the server in a subsequent API call.
campaign
.
ClearName
();
// Set the campaign to empty string value. This value will be
// sent to the server if you use this object in a subsequent API call.
campaign
.
Name
=
""
;
// This will throw a runtime error. Use ClearName() instead.
campaign
.
Name
=
null
;
Repeated types
A field array is represented in the Google Ads API as a readonly RepeatedField
.
An example is a campaign's url_custom_parameters
field being a repeated field,
so it's represented as a readonly RepeatedField<CustomParameter>
in the .NET
client library.
The RepeatedField
implements the IList<T>
interface.
There are two ways to populate a RepeatedField
field.
Older C# version: Add values using AddRange method
An example is given below.
Campaign
campaign
=
new
Campaign
()
{
ResourceName
=
ResourceNames
.
Campaign
(
customerId
,
campaignId
),
Status
=
CampaignStatus
.
Paused
,
};
// Add values to UrlCustomParameters using AddRange method.
campaign
.
UrlCustomParameters
.
AddRange
(
new
CustomParameter
[]
{
new
CustomParameter
{
Key
=
"season"
,
Value
=
"christmas"
},
new
CustomParameter
{
Key
=
"promocode"
,
Value
=
"NY123"
}
});
Newer C# versions: Use collection initializer syntax
// Option 1: Initialize the field directly.
Campaign
campaign
=
new
Campaign
()
{
ResourceName
=
ResourceNames
.
Campaign
(
customerId
,
campaignId
),
Status
=
CampaignStatus
.
Paused
,
// Directly initialize the field.
UrlCustomParameters
=
{
new
CustomParameter
{
Key
=
"season"
,
Value
=
"christmas"
},
new
CustomParameter
{
Key
=
"promocode"
,
Value
=
"NY123"
}
}
};
// Option 2: Initialize using an intermediate variable.
CustomParameter
[]
parameters
=
new
CustomParameter
[]
{
new
CustomParameter
{
Key
=
"season"
,
Value
=
"christmas"
},
new
CustomParameter
{
Key
=
"promocode"
,
Value
=
"NY123"
}
}
Campaign
campaign1
=
new
Campaign
()
{
ResourceName
=
ResourceNames
.
Campaign
(
customerId
,
campaignId
),
Status
=
CampaignStatus
.
Paused
,
// Initialize from an existing array.
UrlCustomParameters
=
{
parameters
}
};
OneOf types
Some fields in the Google Ads API are marked as OneOf
fields, meaning that the field
can hold different types but only one value at a given time. OneOf fields are
similar to union type in C.
The .NET library implements OneOf fields by providing one property for each type of value that can be held in a OneOf field, and all the properties updating a shared class field.
For example, the campaign's campaign_bidding_strategy
is marked as a OneOf
field. This class is implemented as follows (code simplified for brevity):
public
sealed
partial
class
Campaign
:
pb
::
IMessage<Campaign>
{
object
campaignBiddingStrategy_
=
null
;
CampaignBiddingStrategyOneofCase
campaignBiddingStrategyCase_
;
public
ManualCpc
ManualCpc
{
get
{
return
campaignBiddingStrategyCase_
==
CampaignBiddingStrategyOneofCase
.
ManualCpc
?
(
ManualCpc
)
campaignBiddingStrategy_
:
null
;
}
set
{
campaignBiddingStrategy_
=
value
;
campaignBiddingStrategyCase_
=
CampaignBiddingStrategyOneofCase
.
ManualCpc
;
}
}
public
ManualCpm
ManualCpm
{
get
{
return
campaignBiddingStrategyCase_
==
CampaignBiddingStrategyOneofCase
.
ManualCpm
?
(
ManualCpm
)
campaignBiddingStrategy_
:
null
;
}
set
{
campaignBiddingStrategy_
=
value
;
campaignBiddingStrategyCase_
=
CampaignBiddingStrategyOneofCase
.
ManualCpm
;
}
}
public
CampaignBiddingStrategyOneofCase
CampaignBiddingStrategyCase
{
get
{
return
campaignBiddingStrategyCase_
;
}
}
}
Since OneOf properties share storage, one assignment can overwrite a previous assignment, leading to subtle bugs. For example,
Campaign
campaign
=
new
Campaign
()
{
ManualCpc
=
new
ManualCpc
()
{
EnhancedCpcEnabled
=
true
},
ManualCpm
=
new
ManualCpm
()
{
}
};
In this case, campaign.ManualCpc
is now null
since initializing the campaign.ManualCpm
field overwrites the previous initialization for campaign.ManualCpc
.
Conversion to other formats
You can easily convert protobuf objects to JSON format and in reverse. This is useful when building systems that need to interface with other systems that require data in text-based formats like JSON or XML.
GoogleAdsRow
row
=
new
GoogleAdsRow
()
{
Campaign
=
new
Campaign
()
{
Id
=
123
,
Name
=
"Campaign 1"
,
ResourceName
=
ResourceNames
.
Campaign
(
1234567890
,
123
)
}
};
// Serialize to JSON and back.
string
json
=
JsonFormatter
.
Default
.
Format
(
row
);
row
=
GoogleAdsRow
.
Parser
.
ParseJson
(
json
);
You can also serialize an object to bytes and back. Binary serialization is more memory and storage efficient than JSON format.
GoogleAdsRow
row
=
new
GoogleAdsRow
()
{
Campaign
=
new
Campaign
()
{
Id
=
123
,
Name
=
"Campaign 1"
,
ResourceName
=
ResourceNames
.
Campaign
(
1234567890
,
123
)
}
};
// Serialize to bytes and back.
byte
[]
bytes
=
row
.
ToByteArray
();
row
=
GoogleAdsRow
.
Parser
.
ParseFrom
(
bytes
);