16Jul
2008

Tags: , ,

For a while now I've been interested in learning more about building and consuming REST based web services. Fortunately, many tech giants including Google and Yahoo expose much of their data and functionality through REST based APIs. These powerful APIs, combined with Groovy's concise, readable syntax make it very easy to learn about the REST software architecture approach.

This particular blog entry makes use of Google's Finance Data API. I'll explain how it is possible to programmatically authenticate with Google, create a new stock portfolio, and create positions (buy and sell stocks) within this portfolio by making REST based service calls. I won't dive too deep into the details of the REST architecture, but if you have a general understanding of XML and the HTTP protocol it won't be too difficult to follow along. For more information on REST, please see the links in the Reference section below.

Note: If you want to try the code samples on your own you will need to have a Google Account. To sign up for a free account click here.

Authenticating with Google

In order to use Google's service we must first authenticate by POSTing a query string containing our username, password, service identifier, and source (application name) to the following URL: https://www.google.com/accounts/ClientLogin. This code snippet illustrates how a POST request can be made in Groovy:

static createAuthToken(String username, String password){
    def url = new URL("https://www.google.com/accounts/ClientLogin")
    def connection = url.openConnection()

    def queryString = "Email=${username}&Passwd=${password}" +
                      "&service=finance&source=company-groovyfinance-1.0"

    def returnMessage = processRequest(connection, queryString)

    if(returnMessage != "Error"){
        //the authentication token
        return returnMessage.split(/Auth=/)[1].trim()
    }
}

static String processRequest(connection, dataString){
    connection.setRequestMethod("POST")
    connection.doOutput = true
    Writer writer = new OutputStreamWriter(connection.outputStream)
    writer.write(dataString)
    writer.flush()
    writer.close()
    connection.connect()

    if (connection.responseCode == 200 || connection.responseCode == 201)
        return connection.content.text

    return "Error"
}

In the code above we create a connection to Google's authentication URL and POST the queryString by calling the reusable processRequest() method. Within processRequest() we set the connection's request method type to "POST", create a Writer, and write the data to the supplied connection.

Note: The code example for this blog post can be downloaded in its entirety by clicking the "Download the Code" link in the Reference section below.

If our credentials are valid, Google will respond to our request with a string of name value pairs similar to this:

SID=DQAAAIEAAAIgccs7qKgmwXGagt...lu6fg
LSID=DQAAAIIAAACsegj9oEm0Ob8pz...abyi5
Auth=DQAAAIMAAACgadj9oEm0Ob8pz...AGasG

The only piece of information we are interested in is the authorization token value that follows the "Auth" label. We will need to use this token in the rest of our requests in order to authenticate with Google.

Creating a Portfolio

When users log into Google Finance for the first time they will be presented by default with an empty portfolio called "My Portfolio". Note: a portfolio is simply a collection of assets (stocks, bonds, mutual funds, cash, etc.).

Empty Portfolio

Let's pretend however that we do not wish to use the default portfolio, but instead want to create our own. To create a new portfolio we simply need to send a well formed Atom XML feed that contains the name of the new portfolio (and optionally a currency code) to this URL: http://finance.google.com/finance/feeds/default/portfolios

static createPortfolio(String authorizationToken, String portfolioName){
    def url =
    	 new URL("http://finance.google.com/finance/feeds/default/portfolios")

    def connection = url.openConnection()
    connection.setRequestProperty("Content-Type", "application/atom+xml")
    connection.setRequestProperty("Authorization",
                                  "GoogleLogin auth=${authorizationToken}")

    def atomString = """<?xml version='1.0'?>
    <entry xmlns='http://www.w3.org/2005/Atom'
    	   xmlns:gf='http://schemas.google.com/finance/2007'
           xmlns:gd='http://schemas.google.com/g/2005'>
        <title type='text'>${portfolioName}</title>
        <gf:portfolioData currencyCode='USD'/>
    </entry>"""

    def returnMessage = processRequest(connection, atomString)

    //Get the id of the newly created portfolio
    if(returnMessage != "Error"){
    	def entry = new XmlSlurper().parseText(returnMessage)
    	def entryId = "${entry.id}"

    	return entryId[entryId.lastIndexOf('/')+1..-1]
    }
}

Once again we create a connection, but this time we also need to set two request header parameters: Content-Type and Authorization. We set these parameters to "application/atom+xml" and "GoogleLogin auth=${authorizationToken}" respectively. Note that the authorizationToken variable stores the authentication token that was returned by the createAuthToken() method.

After the connection is created we again call the processRequest() method that was discussed in the Authenticating with Google section above. If all goes well, Google will create the new portfolio and return an Atom representation of that new portfolio to the client. If we are logged into our web based Google Finance account we can refresh the screen and will notice our newly created portfolio.

Groovy Portfolio Added

Two code features really shine through in the example above: Groovy's Triple Quotes and Groovy's XmlSlurper. The triple quotes surrounding the Atom XML allow us to easily write multi-line XML strings without having to worry about escaping special characters. The XmlSluper meanwhile allows us to easily parse and locate a specific attribute (the portfolio id in this case) within the returned XML string. Imagine how many lines of Java code it would take to recreate this functionality.

Placing an Order

So far our portfolio is pretty boring. Let's create some stock transactions to add some assets into our portfolio.

static createStockTransaction(authorizationToken, tickerSymbol, numberOfShares,
                              transactionType, portfolioId){

    StringBuffer transactionURL = new StringBuffer()
    transactionURL.append("http://finance.google.com/finance/feeds/")
        .append("default/portfolios/${portfolioId}/positions/")
        .append("${URLEncoder.encode(tickerSymbol)}/transactions")

    def url = new URL(transactionURL.toString())
    def connection = url.openConnection()

    connection.setRequestProperty("Content-Type", "application/atom+xml")
    connection.setRequestProperty("Authorization",
                                  "GoogleLogin auth=${authorizationToken}")

    String timeFormat = "yyyy-MM-dd'T'HH:mm:ss.S"
    SimpleDateFormat dateFormatter = new SimpleDateFormat(timeFormat)
    String transactionDate = dateFormatter.format(new Date())

    def atomString = """<?xml version='1.0'?>
    <entry xmlns='http://www.w3.org/2005/Atom'
    	xmlns:gf='http://schemas.google.com/finance/2007'
    	xmlns:gd='http://schemas.google.com/g/2005'>
    	  <gf:transactionData date='${transactionDate}'
    	      shares='${numberOfShares}' type='${transactionType}' />
    </entry>"""

    processRequest(connection, atomString)
}

The concept with this code is basically the same as the portfolio creation example above. We create a connection with the correct Content-Type and Authorization headers, define some Atom XML with attributes about the transaction we would like to make, and then POST the XML to a specific URL. The interesting thing to note about this code is that unlike the other two examples, the URL for creating transactions is not static. Instead, this URL needs to be parameterized with the portfolio id and ticker symbol of the stock you wish to trade: http://finance.google.com/finance/feeds/default/portfolios/<portfolio id>/ positions/<ticker symbol>/transactions.

Method calls to createStockTransaction() might look something like this:

createStockTransaction(authorizationToken, "NASDAQ:JAVA", 10000.00, "Buy", pId)
sleep(2000)
createStockTransaction(authorizationToken, "NYSE:F", 10000.00, "Buy", pId)

This would place an order for 10,000 shares of Sun Microsystems and Ford Motor Company stock. Notice that the ticker symbol must be preceded by the name of the market on which it trades. Therefore the ticker symbol we sent to Google to purchase Sun stock is: NASDAQ:JAVA because Sun trades on the NASDAQ stock exchange. Stocks that trade on the New York Stock Exchange would be preceded by the acronym: NYSE (i.e. Ford = NYSE:F). Also notice that it is a good idea to "sleep" between service calls because sending too many requests to Google at once will result in errors.

When we refresh our Google Finance page we will notice these shares placed into our portfolio.

Stocks Purchased

Conclusion

This blog post only skims the surface of what is possible using Google's Finance Data API. The API also allows for RESTful calls to GET, UPDATE and DELETE specific portfolio and transaction feeds. Overall, I've been incredibly impressed by all of the data and functionality made available through Google's Data APIs.

The code provided in this example should give you a solid foundation to start playing around with Google's Finance API, but it is far from bulletproof. For example, I don't really do much in the way of error handling or input validation. So you shouldn't be surprised if things bomb out if you try to sell shares of a stock that you don't own or create a portfolio with the same name as one of your existing portfolios.

The examples I've shown here are very low level because I wanted to learn the basics of REST. A much easier way to implement the same functionality would be to use Google's Data APIs Client Libraries (which by the way work perfectly well with Groovy).

References


Download the Code

Google Data API Developers Guide
Google Finance Developers Guide
Google Finance Reference

Building Web Services the REST Way
REST Wikipedia Entry

Disclaimer

I am in no way endorsing any of the companies mentioned in this blog entry and all company references are for example purposes only.

Share and Enjoy:
  • Print
  • Digg
  • del.icio.us
  • Facebook
  • DZone
  • FSDaily
  • Reddit
  • Slashdot
  • StumbleUpon
  • Technorati
  • Twitter
  1. 11 Responses to “Putting Google Finance to REST with Groovy”

  2. I found your blog on google and read a few of your other posts. I just added you to my Google News Reader. Keep up the good work. Look forward to reading more from you in the future.

    By Susan Kishner on Jul 16, 2008

  3. *** Update ***

    I changed the code in the createAuthToken() method to split the “returnMessage” using a regular expression.

    Old code:
    returnMessage.split(“\n”)[2].split(“=”)[1]

    New code:
    returnMessage.split(/Auth=/)[1].trim()

    I think we can all agree that this should make the code much more readable.

    By Justin on Jul 23, 2008

  4. I’m using google finance for stock portfolios. I can’t figure out how to delete in the program. Please advise.

    J. Henoch

    By j. henoch on Dec 11, 2008

  5. I’m not exactly sure what you are asking. What are you trying to delete? An entire portfolio, a specific transaction, or something else? Also, do you want to know how to do it using the RESTful API or simply by using Google Finance’s interface?

    By Justin Spradlin on Dec 11, 2008

  6. Hi ,

    I am a PHP Developer i need to display the Stock changes in my web site , i tried the Google finance API document but, i cannot able to follow the login authentication please help me to finish up thank you ,

    By damodharan..k on Jul 28, 2009

  7. Great post! I can’t download the source code from your link, can you please make it available again? Thanks.

    By Bobby on Feb 22, 2010

  8. @Bobby

    I’ve updated the link. Sorry for the mix up. Glad you liked the post!

    By Justin Spradlin on Feb 22, 2010

  9. your download link does not work,
    instead i get an error 404
    please fix this issue as your tutorial is a very nice start for using Google services.

    By aerodub on Apr 27, 2011

  10. Hi aerodub,
    I’ve updated the link for the code.

    By Justin Spradlin on Apr 28, 2011

  11. interesting article indeed. though a bit outdated, do you have anything updated on this or would you consider this all to be functional?

    thanks,
    JMM
    CTO – King of All Trades

    By kingofalltrades on Aug 21, 2011

  1. 1 Trackback(s)

  2. Apr 26, 2009:   Groovy: Post to a URL by Matt Stine’s Blog

Post a Comment