Friday, November 18, 2011

Using an external api in a Go web program - urlshortener from Google APIs


In this tutorial, we will look at how to use an external API within our go program. The one that we shall use is the URL Shortener API. You can try its present functionality at http://goo.gl/. Enter a URL like http://golangtutorials.blogspot.com/ and you will see a shorter URL returned, which is much easier to embed, say, in a service like twitter. The technology that Google uses to do this is available to other developers as an api that we can call from our own applications (free up to a specified limit). You can read more about the api itself at http://code.google.com/apis/urlshortener/.

The program itself is fairly simple, so it is a good learning step. Also, I will be using the same example as a starting point for an AppEngine for Go application (see here for AppEngine tutorial). To review what we know so far, it would be good to go over these other tutorials and links:
* writing a web app: http://golangtutorials.blogspot.com/2011/06/web-programming-with-go-first-web-hello.html
* goinstall: http://golangtutorials.blogspot.com/2011/10/go-packages-and-goinstall-creating-and.html
* templates: http://golangtutorials.blogspot.com/2011/06/go-templates.html
* the google-api-go-client: http://code.google.com/p/google-api-go-client/

Step 1: Ensure your environment is setup right

* Setup the environment variable GOPATH to point to a directory of your choice (if you haven’t done so already).
The external source code will be downloaded into this directory $GOPATH/src and the packages also will be installed under this directory $GOPATH/pkg.

Step 2: Install the APIs

* Get the APIs by issuing the following command:
goinstall google-api-go-client.googlecode.com/hg/urlshortener/v1
* This will download the source code for all the apis into $GOPATH/src.
So you should have a whole bunch of directories among which there are also
$GOPATH/src/google-api-go-client.googlecode.com/hg/urlshortener and
$GOPATH/src/google-api-go-client.googlecode.com/hg/google-api
* … and also install the compiled packages into $GOPATH/pkg/"machine_arch"/.
Since I have a Linux machine with a 64 bit processor, I have these new directories and files
$GOPATH/pkg/linux_amd64/google-api-go-client.googlecode.com/hg/google-api.a
$GOPATH/pkg/linux_amd64/google-api-go-client.googlecode.com/hg/urlshortener/v1.a


Step 3: Write code that imports the API and uses it

The API can now be imported using a statement similar to:
import ( urlshortener "google-api-go-client.googlecode.com/hg/urlshortener/v1")

This format of importing a package with a deep or long directory structure allows us to refer to it with a shorter alias. To use a function New within the package google-api-go-client.googlecode.com/hg/urlshortener/v1 can now be referred to as urlshortener.New.

The entire code is given below.
Full program
package main

import (
    "fmt"
    "http"
    "template"
    urlshortener "google-api-go-client.googlecode.com/hg/urlshortener/v1" //import the installed package
)

func main() {
    http.HandleFunc("/", handleRoot)
    http.HandleFunc("/shorten", handleShorten)
    http.HandleFunc("/lengthen", handleLengthen)

    http.ListenAndServe("localhost:8080", nil)
}

// the template used to show the forms and the results web page to the user
var rootHtmlTmpl = template.Must(template.New("rootHtml").Parse(`
<html><body>
<h1>My URL Shrtnr</h1>
{{if .}}{{.}}<br /><br />{{end}}
<form action="/shorten" type="POST">
Shorten this: <input type="text" name="longUrl" />
<input type="submit" value="Give me short URL" />
</form>
<br />
<form action="/lengthen" type="POST">
Expand this: http://goo.gl/<input type="text" name="shortUrl" />
<input type="submit" value="Give me long URL" />
</form>
</body></html>
`))

func handleRoot(w http.ResponseWriter, r *http.Request) {
    rootHtmlTmpl.Execute(w, nil)
}

func handleShorten(w http.ResponseWriter, r *http.Request) {
    longUrl := r.FormValue("longUrl") //get the value of the text field with name longUrl in the form
    urlshortenerSvc, _ := urlshortener.New(http.DefaultClient) //use the default client that is available in the http package and create a new instance of the url shortener service
    url, _ := urlshortenerSvc.Url.Insert(&urlshortener.Url {
        LongUrl: longUrl,
    }).Do() // fill in the Url data structure with the given long url and call the service
    rootHtmlTmpl.Execute(w, fmt.Sprintf("Shortened version of `%s` is : %s", longUrl, url.Id))
}

func handleLengthen(w http.ResponseWriter, r *http.Request) {
    shortUrl := "http://goo.gl/" + r.FormValue("shortUrl") // get the value of the text field with name shortUrl in the form
    urlshortenerSvc, _ := urlshortener.New(http.DefaultClient)
    url, err := urlshortenerSvc.Url.Get(shortUrl).Do()
    if err != nil {
        fmt.Println("error: %v", err)
        return
    }
    rootHtmlTmpl.Execute(w, fmt.Sprintf("Longer version of %s is : %s", shortUrl, url.LongUrl))
}


Step 4: Compile, link the code, and execute

To compile and link the program from the command line, you will need to indicate the path where the libraries are available. I used the following commands in my Linux bash shell - if your OS/shell is different or if your file is named differently, use the appropriate ones.

* To compile I used: 6g -I $GOPATH/pkg/linux_amd64 urlshortener.go
* To link I used: 6l -L $GOPATH/pkg/linux_amd64 urlshortener.6
* To execute it I did: ./6.out (ensure that you do not have any other applications running on http://localhost:8080 or this step will fail)
* To test it, I navigate to the web page: http://localhost:8080/.

Step 5: Test it …

You can test out your program now by entering a link like "http://www.google.com/" in the "Shorten this:" textbox. Clicking on the "Give me short URL" button should give you the result below.
Shortened version of `http://www.google.com/` is : http://goo.gl/fbsS

You can also try the reverse by entering "fbsS" in the "Expand this:" textbox and clicking on "Give me long URL" button. The response ought to be:
Longer version of http://goo.gl/fbsS is : http://www.google.com/

6 comments:

  1. it's not work in go v1
    after update some code to go v1
    and when install API
    go get code.google.com/p/google-api-go-client/urlshortener/v1
    This error message appears to me

    "# cd .; hg clone -U https://code.google.com/p/google-api-go-client E:\Go
    Setup\src\pkg\code.google.com\p\google-api-go-client
    package code.google.com/p/google-api-go-client/urlshortener/v1: exec: "hg": exec
    utable file not found in %PATH%"

    I use windows OS

    ReplyDelete
    Replies
    1. after install Mercuria work fine

      Delete
  2. I have mercurial installed but I still get this error. I can't compile the code because of that:

    6g: command not found

    Can you help me out?

    ReplyDelete
  3. As of know this works: go get google.golang.org/api/urlshortener/v1

    ReplyDelete
  4. Ugh, you also need an api key (OAuth2) to access the shortener service now.

    ReplyDelete

If you think others also will find these tutorials useful, kindly "+1" it above and mention the link in your own blogs, responses, and entries on the net so that others also may reach here. Thank you.