Discover v2009: Error handling in BulkMutateJobService.

Wednesday, April 28, 2010


In our previous blog post, we discussed how v2009 error handling works in synchronous APIs. In this blog post, we cover asynchronous error handling in BulkMutateJobService. If you are new to BulkMutateJobService, check out our introductory blog post and code.google.com article.

Due to its asynchronous nature, error handling in BulkMutateJobService is slightly different than in other services. Instead of throwing an ApiError object, BulkMutateJobService returns FailureResult or BatchFailureResult objects as its operation results. These objects in turn contain the relevant ApiErrors. BulkMutateJobService processes the operations within an operation stream in multiple atomic batches. If there is even one faulty operation in a batch, it causes the other non-faulty operations in the batch to fail as well. When a batch of n operations fails, you will get one FailureResult and n - 1 BatchFailureResults as results for the failed batch of operations. The FailureResult object will always be first in the batch, and will contain one ApiException object. The ApiException contains all the errors for the entire batch of operations, just like for other services. This will be followed by n - 1 BatchFailureResults, which can be viewed as placeholders, one for each operation in the batch.

For instance, assume that you are trying to create the following 9 text ads in a single OperationStream. For the purposes of this example, assume that the system processes operations in batches of 3. The errors are highlighted in red.



































































IndexAdDestination UrlError
0New York Budget Hotel
Clean and close to subway.
Students save 20%!
www.example.com/NewYork
http://www.example.com/NewYork

1Book New York Hotel Deals
Research your New York Stay. Deals
up to 70% from example.com.
www.example.com/NewYork
http://www.example.com/NewYork

2Hotels In New York
Book your hotel room online at a
lower price via example.com!!
www.example.com/NewYork
http://www.example.com/NewYork
Excessive punctuation in description2
3Manhattan Best Hotel
Experience the Best of Manhattan
For Rates As Low As $239/Night.
www.example.com/NewYork
www.example.com/NewYork
Missing schema in destination url.
4New York City Hotels Discount
Discounted Rooms in New York City.
Get Lowest Rates Available Today.
www.example.com/NewYork
http://www.example.com/NewYork

5New York City Hotels
Stay Smart in New York NY.
Free internet & breakfast bar.
www.example.com/NewYork
http://www.example.com/NewYork

670% Off New York Hostels
Why Pay More? From $10 We Guarantee
Lowest Prices - From 1 Night
www.example.com/NewYork
http://www.example.com/NewYork

7Stylish New Hotel in NYC
Enjoy Four-Star Amenities & Service
Chelsea/Fashion District. Book Now!
www.example.com/NewYork
http://www.example.com/NewYork

8Budget Lodging in NYC
Comfortable, Clean Modern Economy
Hotel.Great Downtown Location!
www.example.com/NewYork
http://www.example.com/NewYork





When BulkMutateJobService processes these operations, it will return the following results:


Result[0]: FailureResult.
ApiException.errors has one ApiError
PolicyViolationError @ operations[2].operand.ad.description2
Result[1]: BatchFailureResult, operationIndexInBatch = 1
Result[2]: BatchFailureResult, operationIndexInBatch = 2

Result[3]: FailureResult.
ApiException.errors have 1 ApiError
AdError.URL_NO_SCHEME @ operations[0].operand.ad.url
Result[4]: BatchFailureResult, operationIndexInBatch = 1
Result[5]: BatchFailureResult, operationIndexInBatch = 2

Result[6]: ReturnValueResult, successfully created Ad.
Result[7]: ReturnValueResult, successfully created Ad.
Result[8]: ReturnValueResult, successfully created Ad.

As shown in the results above, there is a 1:1 correspondence between the number of operations and number of results. You can get the successful operations by scanning the return value for results which are not FailureResult or BatchFailureResult (operations 6, 7 and 8 in this case). Then, scan through the results to locate FailureResult objects (which always appear at the beginning of the failed batch) to get the operation that actually failed (operations 2 and 3 in this case). You can now pick the failed operations that do not correspond to the ones obtained from FailureResult, and make a new job for them (0, 1, 4, 5). Note that the OGNL path in FailureResult is relative to the batch and not the operationstream, so you have to offset it by the index of FailureResult to get the failed operation (e.g. Results[3] is a FailureResult and its OGNL path is operations[0].operand.ad.url, so the failing operator in the original list is 3 + 0 = operations[3]).

A BulkMutateJob may also return the following error results, even though they're not common:

LostResult: This happens when BMJS has lost results for some of a job's operations. You can recover from this error by checking numFailedOperations and numUnprocessedOperations for the job. If both are zero, or if the number of errors in ApiError matches numFailedOperations, then the operations were successful, but the results are missing. In any other case, you have to retrieve the entities that were targeted by the operations and see if the operation actually succeeded or not.

UnprocessedResult: This indicates that the mutate operation was not processed. This could happen because the workflow implementation prevented the operation from being processed (e.g. the operations exceed API quota). You can recover from this issue by checking the job status, making sure that you have sufficient API quota left, and simply retrying the operations in a new job.

In an upcoming blog post, we will cover the most common errors you may get in v2009, and how to address them. We've included support for error handling in all of our client libraries to help get you started, so please try it out and share your feedback with us on the forum or the projects' issue trackers.

-- Anash P. Oommen, AdWords API Team

Introducing preferred AdWords API pricing for agencies

Monday, April 26, 2010


Today, we're announcing preferred AdWords API pricing for agencies and developers of search engine marketing (SEM) tools. With preferred pricing, this important group of developers will get free API units based on managed client spend.

As an agency or a developer of SEM tools, you are eligible to apply for preferred pricing if:
We'll start accepting your applications for preferred pricing on May 26, 2010 and will respond with the status of your application starting July 1, 2010.

Along with this change, we have updated the AdWords API terms and conditions and the required minimum functionality (RMF). We've made a couple of changes to the RMF, based on the feedback you shared with us after we first published the RMF.

First, we're clarifying that the RMF does not apply to Internal-only AdWords API Clients. This means that you're not required to implement the RMF features within internal tools that are solely used by employees of your company. Please review the terms and conditions to determine which tools might qualify as Internal-only AdWords API Clients. Second, in this round of updates to the RMF, we are making some features optional. For example, demographic targeting, which was previously a required feature, is now optional.

We hope that the changes we're making with preferred pricing will encourage you to experiment with new strategies, expand the functionality of your tools, and build more comprehensive client campaigns, without worrying about API costs. Please review the preferred pricing web site and the FAQs for more information on the requirements and the application process. If you have questions or feedback on these changes, please don't hesitate to contact your Google representative.

– Shreyas Doshi, Product Manager

Most v13 services turned off today

Thursday, April 22, 2010


You might remember that six months ago we announced that on April 22, 2010 we would be sunsetting many v13 services. Since then, we’ve posted reminders over the last 100 days right here on the blog. It’s finally April 22, so today we’re sunsetting the following v13 services:

  • CampaignService
  • AdGroupService
  • CriterionService
  • AdService
  • InfoService
  • KeywordToolService
  • SiteSuggestionService
If you’re still using any of these services, you’ll start to see your calls fail with error code 213. Migrate to the v200909 version of the API to avoid failed calls. Review our per-call migration guide to move your applications over to v2009.

Please note that AccountService, ReportService, and TrafficEstimatorService will remain available in version v13 of the API until we’ve provided this functionality in the new API. We’ll give you at least four months to migrate these last three v13 services once their replacements are available.

As always, please ask questions and share your feedback on the developer forum. Our team is happy to answer questions about v2009 and starting today, is no longer supporting questions about the v13 services that we’ve sunset.

– Jason Shafton, Product Marketing Manager

Discover v2009: Error handling

Wednesday, April 14, 2010


As with any programming system, error handling is a critical part of the AdWords API as well. In v13, we used to describe every error by its own error code. While this was simple and handy, the API provided less additional information about the error itself. In v2009, we decided instead to use error types with additional fields to describe the specifics of each error. The new error handling system gives you the type of error (e.g. PolicyViolationError), the cause of error (e.g. the editorial policy that was violated), the field that triggered the error and so forth. In this blog post, I'll cover the v2009 error handling in detail, with focus on v2009 synchronous services.

Error handling in v13 and v2009 APIs

To show the difference in error handling between v13 and v2009, consider the following v13 code to create a campaign.

try {
AdWordsUser user = new AdWordsUser();
CampaignInterface service =
(CampaignInterface) user.getService(AdWordsService.V13.CAMPAIGN_SERVICE);
Campaign campaign = new Campaign();
campaign.setName("New campaign");
campaign.setBudgetPeriod(BudgetPeriod.Daily);
campaign.setBudgetAmount(50L);
campaign = service.addCampaign(campaign);
} catch (ApiException e) {
for (ApiError error : e.getErrors()) {
System.out.println("There is an error on argument " + error.getIndex()
+ ". Error code is " + error.getCode()
+ ", details are \"" + error.getDetail()
+ "\", field is " + error.getField());
}
}

This code generates the following output:

There is an error on argument 0. Error code is 34, details are "Money amount less than CurrencyMinCpc.", field is budget.

The same code in v2009 is given below:

try {
user = new AdWordsUser();
CampaignServiceInterface service = (CampaignServiceInterface)
user.getService(AdWordsService.V200909.CAMPAIGN_SERVICE);
Campaign campaign = new Campaign();
campaign.setName("New campaign");
campaign.setBiddingStrategy(new ManualCPC());
campaign.setBudget(new Budget(BudgetBudgetPeriod.DAILY,
new Money(null, 50L), BudgetBudgetDeliveryMethod.STANDARD));
CampaignOperation operation = new CampaignOperation();
operation.setOperator(Operator.ADD);
operation.setOperand(campaign);
campaign = service.mutate(new CampaignOperation[] {operation}).getValue()[0];
} catch (ApiException e) {
for (ApiError error : e.getErrors()) {
System.out.println("There is an error on argument " + error.getFieldPath()
+ ".");
if (error instanceof BudgetError) {
BudgetError budgetError = (BudgetError) error;
System.out.println("Reason is " + budgetError.getReason());
}
}
}

The code generates the following output:

There is an error on argument operations[0].operand.budget. Reason is NON_MULTIPLE_OF_MINIMUM_CURRENCY_UNIT.

As shown in the code above, v2009 returns an error object derived from ApiError, with an appropriate error reason that gives more insight into why the error occurred. This allows you to write a switch-case to handle error categories and reasons that are significant for your program more elegantly than in v13. Also, the list of exceptions raised by a service are available along with the service documentation. For instance, all the exceptions that can possibly be raised by CampaignService are listed at http://code.google.com/apis/adwords/v2009/docs/reference/CampaignService.html#errors

Retrieving the violating field using FieldPath

FieldPath is another useful item you get from a v2009 error. FieldPath stores the OGNL path to the field that caused the violation. OGNL stands for Object-Graph Navigation Language; it is an expression language for getting and setting properties of objects. You can use it as a debugging aid while developing your application, retrieve the value of the violating field, etc. For instance, the following code shows how to retrieve the value of budget that caused the error using the library from opensymphony.

try {
OgnlContext ognlContext = new OgnlContext();
ognlContext.put("operations", operations);
Object value = Ognl.getValue(error.getFieldPath(), ognlContext);
System.out.println("Violating field is " + error.getFieldPath()
+ " and value is " + value);
} catch (OgnlException e) {
e.printStackTrace();
}

This code will print the output as

Violating field is operations[0].operand.budget and value is 50.

In case you are interested in just the index of the violating operation, you can evaluate it using a simple regex as follows:

public static int getOperationsIndex(String ognl) {
String OPERATIONS_INDEX_REGEX = "^operations\\[(\\d+)\\]";
Matcher m = Pattern.compile(OPERATIONS_INDEX_REGEX).matcher(ognl);
if (m.find()) {
return Integer.parseInt(m.group(1));
} else {
return -1;
}
}

Validating API calls using validateOnly

AdWords API also allows you to validate your API calls to see if the request will generate any errors or not. You can validate any API call by setting the validateOnly SOAP header to true and making the API call as usual. If the request contains errors, you will get ApiError objects. If the request is fine, no errors are thrown, and the API call doesn't perform any action either. In addition to providing a way to validate your API calls, validateOnly is significantly cheaper than normal calls. You can refer to the rate sheet to calculate how many API units a validateOnly call will cost you. For more details on how to use validateOnly headers, you can refer to our blog post here

In our next blog post, we will cover how v2009 error handling works in BulkMutateJobService. We've included support for error handling in all of our client libraries to help get you started, so please try it out and share your feedback with us on the forum.

-- Anash P. Oommen, AdWords API Team

14 days left to migrate to v2009

Thursday, April 08, 2010


If you haven’t migrated to the new v2009 AdWords API yet you have only 14 days left to do so. Developers that don’t migrate by April 22 will experience failed calls to most v13 services. The only v13 services that will remain accessible are AccountService, ReportService, and TrafficEstimatorService.

Have questions about migrating? Review the per-call migration guide, visit the developer forum and follow us on Twitter.

– Jason Shafton, Product Marketing Manager

AdWords Downtime: April 10th, 10am-2pm PDT

Tuesday, April 06, 2010


We'll be performing routine system maintenance on Saturday, April 10th from approximately 10:00am to 2:00pm PDT. You won't be able to access AdWords or the API during this time frame, but your ads will continue to run as normal.

Best,
- Eric Koleda, AdWords API Team