Sunday, October 30, 2011

Analysing a Google AppEnginge for Go program

In this section, we shall look at an existing demo program that we ran in the Installation and Setup tutorial. This will be a good place to start analysing and understanding Go programs for the Google AppEngine and will allow us to move on to larger programs of our own.

Directory Structure

The list of files under google_appengine/demos/helloworld is as shown below:
helloworld/favicon.ico
helloworld/app.yaml
helloworld/helloworld/
helloworld/helloworld/helloworld.go

A side note: When you write your own programs later, note that only the app.yaml has to be named exactly like that. All other files and folders can take whatever name you prefer and they do not have to match with each other in folder name, file name, or package name.

The .yaml file

The .yaml file is a configuration file. The AppEngine that hosts and executes your programs reads and interprets this file when you upload your application to the AppEngine for it to be hosted, and also when it is executed as and when users access it. A comprehensive definition of the possible contents of the .yaml file is available at appconfig. I shall only attempt to cover the relevant sections for a beginner’s understanding of the .yaml file. The contents of the file for this program are as shown below. I have added comments in addition to the original file after the #.

application: helloworld # A unique identifier that distinguishes this application among the various AppEngine applications
version: 1 # The version of your application. 
runtime: go # The programming language used by this application.
api_version: 3 # The version of the AppEngine that this application uses.

handlers: # Routing of different urls to different types of handlers, e.g. maybe to a go program or directly to the static file.
- url: /favicon\.ico # If there is a URL of the form ‘application_root’/favicon.ico, then ...
  static_files: favicon.ico # … serve this static file back to the browser.
  upload: favicon\.ico # When uploading from your local directory to AppEngine, these are the local files that have to be updated.

- url: /.* # For all other URL patterns … 
  script: _go_app # … run the main application.


To give a few more details …
application: When you upload your locally developed code to the AppEngine for hosting, this is the unique identifier that is used, and you will be prompted for it each time you create a new application on the AppEngine Administration Console. While you are developing and testing programs locally, this does not matter much.

version: Your application versioning information can contain alphanumeric characters, and hyphens. You can have any number of versions uploaded to the AppEngine but only one of them can be set as default. This allows you to create versions for testing (say like 3-01-8202-test) before being publicly deployed as the default.

runtime: Since we are working with go, "go" is what we put here. As of this writing, the AppEngine also supports Java and Python.

api_version: As the go language and the AppEngine continues to evolve, there are changes and incompatibilites between versions. Therefore you need to specify which of the api_versions you are using. As of this writing in October 2011, the Go language and the AppEngine for Go is still experimental and changes will be faster and previous versions will be deprecated fairly quickly. The supported versions of the AppEngine is usually announced and available in the appropriate Google Groups: google-appengine-go.

handlers: This section mainly contains regular expressions which are compared, in the order of appearance within the yaml file, with the URL that tries to access the application. This will interpret the part of the URL following the application id, and depending on which is matched the appropriate static files are served or the go program is run. You could imagine that this section is like a switch-case satatement in Go where the incoming URL is switched against the regular expressions in the case/- url: statement, and then the first matching block is executed.

static_files: Certain files like images or pdfs are usually non-changing. These are treated differently as they can be optimized for returning data to the browser. For example, since they are usually unchanging, these files could be copied across different AppEngine servers in different geographic locations, allowing them to be served faster to the user. In this example there is only the image file favicon.ico that is static and it is also in the application root directory within the AppEngine. Typically though, you would want it in a separate directory which is by convention named static.

upload: This value defines what files will be uploaded from your local development environmen to the AppEngine server when the application is deployed each time. In this particular case it is saying that only the local file favicon.ico is to be uploaded. If instead you wrote images/(*.ico|*.gif|*.jpg), it will upload all these types of files within the local images directory onto the AppEngine server.

script: _go_app: This exact string is required when testing the application locally with dev_appserver.py but is not used by the AppEngine server.

For the full yaml specification, you can refer to the site yaml.org.

Checking URLs and URL handlers

In case URL handlers are new to you, let’s just go over them once to see how they work. First run the AppEngine application locally as below from within the google_appengine/demos directory:

At this point, if your application has run properly, you can navigate to http://localhost:8080/ to check that it is working as we saw in Installation and Setup tutorial. Now let’s try some others.

Because of url: /favicon\.ico and static_files: favicon.ico you should be able to see that file being served to the browser by following the link http://localhost:8080/favicon.ico. It is served statically to the browser, but the user will not have a way of knowing that.

Because of - url: /.* and script: _go_app, which is a catch all for all URLs, provided that it is not already handled by a previous url handler, all other URLs will be directed to the main application. So all of the below and all other valid URLs (except http://localhost:8080/favicon.ico) that you can think of running at this server and port will be redirected to the main application.
http://localhost:8080/
http://localhost:8080/abcd
http://localhost:8080/something/somethingelse
http://localhost:8080/favicon.icoandmore

The Go code

The Go code itself in this case is a very simple web application. You can read through the other writeup on an introduction to web applications at: Web programming with Go - first web Hello World. I have reproduced the code here with some comments that might be helpful if you are fairly new to web programming with Go.

Full program
package helloworld

import (
 "fmt"
 "http" // import standard http package
)

func init() {
 http.HandleFunc("/", handle) // define the main initialization function.  This one defines that all incoming requests are to be passed on to the "handle" function below.
}

func handle(w http.ResponseWriter, r *http.Request) {
 fmt.Fprint(w, "Hello, World! 세상아 안녕!") // send back a small html stream with a greeting
}

An important side note. Go coding for the web and for the AppEngine is very simple to get started with. Even for absolute beginners. I would strongly encourage you to just go for it and try it out. Most of what I have gone into detail here is boilerplate code that one tends to reuse, and the long-ish explanation of the syntax within this particular write-up should be mostly seen for reference when you have a doubt.

1 comment:

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.

Note: Only a member of this blog may post a comment.