Getting started with the AdWords API

Mar 17
2016

Actually, I have a project where I have to retrieve Google AdWords statistic data and store it locally to generate reports.

Unfortunately, I lost a lot of time to find out how to start. Therefore you can find here the most important things from the view of a Windows programmer.

1) request an API token. Google ask something from you, like the use you make, if your software will be distributed, if you plan only read access or also to write. You have also to write a short project description. And if you don’t use your API token for more as 3 months, they will ask you the reason. More informations are here:
https://developers.google.com/adwords/api/docs/signingup

2) decide how you will authenticate. OAuth2 is not very simple to understand. Unfortunately, I had opted first for a service authentication. This one is very complicated and you need a Google Apps domain for it, i.e. one of your domains must be registered for a Google cloud service like GMail or Apps. So my recommendation is to use the APPLICATION authmode.

3) on the developers console https://console.developers.google.com you need then to request a new client ID – as type I opted for “OTHER”, as my project is neither a web project, nor a mobile app.

4) for the authentication you need basically 4 things: your API token, a client ID, a client secret and a refresh token. The API token you should have from step 1, client ID and client secret come from step 3, and the refresh token will be described later.

5) generate an AdWords account that has read-only access to the Adwords accounts you need – if you are a developer like me, ask the Adwords guys of your company.

6) download the client libraries here https://github.com/googleads/googleads-dotnet-lib. I would recommend to download the entire project as ZIP and build the client libraries yourself – open the Visual Studio solution file and build all. In this solution you will find a lot of useful things: not only the complete source code of the client libraries, but also samples in C# and VB.NET

7) the OAuth2 flow is not so easy to implement – I have used the OAuthTokenGenerator application from the client libraries from step 6. This application (beware: you have to start this application with elevated rights as it uses internally the httpListener class!) gives you the last pieces needed for authentication: the refresh token

8) use the samples from the client libraries to understand how the entire API works. It is very well documented, and the fact that you have the sources is very helpful. For the authentication best you use the app.config file (yourApplication.exe.config), copy it from the sample in the client library and replace the authentication data

9) last error I made: the AdWords account I used had no campaigns in it since it was the account of the company itself, I had to use one of the customer accounts and set it not in the .config file, but in my program. How this can be accomplished, is documented in the app.config file.

I have to make a compliment to Google: they are very helpful, the API is well documented and you have the full sources to it.

httpListener class in Vulcan.NET/X#

Mar 05
2016

This is code for a Vulcan.NET or X# Listener class (ported over from C#):


// Application : HttpListener
// httpListener.prg , Created : 16.02.2016 08:37
// User : Wolfgang
// C# code see here:
// http://mikehadlow.blogspot.it/2006/07/playing-with-httpsys.html
//
// to make it run without admin rights you need something like this one:
// netsh http add urlacl url="http://*:8080/" user=[username] listen=yes

#using System
#using System.Net
#using System.Text
#using System.IO
#using VulcanHttpListener.riedmann.it

begin namespace VulcanHttpListener.riedmann.it

function Start() as void
 local oProgram as MainProgram

 oProgram := MainProgram{}
 oProgram:Start()

 return

class MainProgram
 protect _oListener as HttpListener

 constructor()

  _oListener := HttpListener{}

 return

 method Start() as void

  _oListener:Prefixes:Add( "http://*:8080/" )
  _oListener:Start()
  Console.WriteLine( "Listening on port 8080, hit enter to stop" )
  _oListener:BeginGetContext( AsyncCallback{ self:GetContextCallback }, null )
  Console.ReadLine()
  _oListener:Stop()

 return

 method GetContextCallback( oResult as IAsyncResult ) as void
  local oContext as HttpListenerContext
  local oRequest as HttpListenerRequest
  local oResponse as HttpListenerResponse
  local oSB as StringBuilder
  local oString as string
  local oBuffer as byte[]
  local oOutput as Stream

  oContext := _oListener:EndGetContext( oResult )
  oRequest := oContext:Request
  oResponse := oContext:Response

  oSB := StringBuilder{}
  oSB:Append( e"\n" )
  oSB:AppendFormat( e"HttpMethod: {0}\n", oRequest:HttpMethod )
  oSB:AppendFormat( e"URI: {0}\n", oRequest:Url:AbsoluteUri )
  oSB:AppendFormat( e"Local path: {0}\n", oRequest:Url:LocalPath )
  oSB:Append( e"\n" )
  foreach cKey as string in oRequest:QueryString:Keys
   oSB:AppendFormat( e"Query: {0} = {1}\n", cKey, oRequest:QueryString[cKey] )
  next
  oSB:Append( e"\n" )

  oString := oSB:ToString()
  oBuffer := System.Text.Encoding.UTF8:GetBytes( oString )
  oResponse:ContentLength64 := oBuffer:Length
  oOutput := oResponse:OutputStream
  oOutput:Write( oBuffer, 0, oBuffer:Length )

  _oListener:BeginGetContext( AsyncCallback{ self, @GetContextCallback() }, null )

  return

end class

end namespace