This tutorial is almost exactly the same as http://golangtutorials.blogspot.com/2011/11/using-external-api-in-go-web-program.html, except that we will be doing the same program for the AppEngine. There are a few differences on how to make it work, so I shall, even at the cost of repetition for those who are coming directly to this page for reference, go over the technical essentials again. But I would urge you to read the above tutorial first.
Purpose of this program: do our own urlshortener application using the Google APIs, but using the Google AppEngine platform.
As in the other tutorial, to review what we know so far, it would be good to go over these other tutorials and links:
* analysing an AppEngine for Go web app: http://golangtutorials.blogspot.com/2011/10/analysing-google-appenginge-for-go.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"/
. The AppEngine however does not use these installed packages. We will be using only the source code as shown in step 3.
Note: this step is different from other tutorial
Step 3: Create the directory structure and copy api source
AppEngine programs are run from a directory. So create a directory with a name of your choice - I have called my directoryurlshrtnrprj
. Into this directory copy the source files of the downloaded API starting with and including the google-api-go-client.googlecode.com
directory. You can find this below $GOPATH/src
. For this tutorial’s program you need only two source sub directories:google-api-go-client.googlecode.com/hg/urlshortener
andgoogle-api-go-client.googlecode.com/hg/google-api
.Note that the “examples" directory should be deleted even if the others remain. This is because this directory also has a .go file with the init() function which is used by the AppEngine to start the application, and if the directory is not deleted, this other program might be started by the AppEngine.
If you have other files or folders also like _obj, .6, etc., don’t worry as it won’t affect your program as they are recompiled (except the “examples" directory under google-api-go-client.googlecode.com/hg which has to removed).
I’ll list my directory structure thus far for your reference:
urlshrtnrprj/google-api-go-client.googlecode.com/hg/urlshortener/v1
urlshrtnrprj/google-api-go-client.googlecode.com/hg/urlshortener/v1/Makefile
urlshrtnrprj/google-api-go-client.googlecode.com/hg/urlshortener/v1/urlshortener-gen.go
urlshrtnrprj/google-api-go-client.googlecode.com/hg/urlshortener/v1/urlshortener-api.json
urlshrtnrprj/google-api-go-client.googlecode.com/hg/google-api/Makefile
urlshrtnrprj/google-api-go-client.googlecode.com/hg/google-api/googleapi.go
Step 4: Write the code that imports the API and uses it, and app.yaml configuration file
The API can now be imported using a statement similar to:import ( urlshortener "google-api-go-client.googlecode.com/hg/urlshortener/v1")
I’ve created a directory called
gocode
for my .go files. You can name it whatever you want though. The entire .go code is given below. There are only two changes from the regular web app in the related tutorial - change the name of the package from main, and change func main()
to func init()
.urlshrtnrprj/gocode/urlshortener.go
package urlshrtnrpkg //has to be changed from main to something else import ( "fmt" "http" "template" urlshortener "google-api-go-client.googlecode.com/hg/urlshortener/v1" //import the installed package ) func init() { // has to be changed from main to init 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)) }
You also need the application configuration file which is given below.
urlshrtnrprj/app.yaml
application: urlshrtnrchk version: 0-1-test runtime: go api_version: 3 handlers: - url: /.* script: _go_app
At this point my directory contents are
urlshrtnrprj/app.yaml
urlshrtnrprj/gocode/urlshortener.go
urlshrtnrprj/google-api-go-client.googlecode.com/hg/urlshortener/v1/Makefile
urlshrtnrprj/google-api-go-client.googlecode.com/hg/urlshortener/v1/urlshortener-gen.go
urlshrtnrprj/google-api-go-client.googlecode.com/hg/urlshortener/v1/urlshortener-api.json
urlshrtnrprj/google-api-go-client.googlecode.com/hg/google-api/Makefile
urlshrtnrprj/google-api-go-client.googlecode.com/hg/google-api/googleapi.go
Step 5: Execute and test
To compile and execute the entire program via AppEngine, rundev_appserver.py
giving your project directory as the argument.
* To execute it I did: dev_appserver.py urlshrtnrprj
(ensure that you do not have any other applications running on http://localhost:8080 or this step will fail)* I will now to be able to navigate to our application web page: http://localhost:8080/.
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/
My hero! Thanks man...
ReplyDelete