Creating a static server in Go for Google App Engine

Posted: Saturday, 3 May 2014

Fork me on GitHub
Admittedly, fighting through the jungles of a new programming language will always be a challenge, and although new programming languages attempt to be as easy-to-understand and usable as possible, unless you're using a product like Visual Studio - where "programming" consists of drag and drop, double click and a few lines of code - it's not going to be easy.

Google recently announced the inclusion of Go into their Google App Engine service, but porting code from one language to another will be an uphill battle. Particularly porting Python code to Go. Would that even be possible?
Both programming languages are fundamentally different, and follow different paradigms, but both can perform the same task of serving data online.

Since Go is so different to Python, it's best to start from the very beginning.

One of the basic necessities of all web servers is a static server.
With Google App Engine, you have two choices in creating static servers - either by creating app.yaml rules that point to its respective resources, or you can take the more flexible approach by letting the underlying programming language (in this case, Go) take care of resource handling.

The latter allows for headers to be manipulated and mimtypes/Content-Type to be easily set.
The official Google App Engine documentation about Go contains a little demo that shows the handling of URLs.
package hello

import (
    "fmt"
    "net/http"
)

func init() {
    http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello, world!")
}
https://developers.google.com/appengine/docs/go/gettingstarted/helloworld
Interestingly enough, the "handler" function is called at every instance of the server's url points. Visiting /nonexistent url will still return "Hello, world!" in your web browser
Google App Engine's Go is different to the default, vanilla, version of Go lang, in which the application does not launch with the "main" function, but the "init" function. Even worse, Google App Engine's Go does not support listening to sockets, and so code like the following will not work without modification!
package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

http://golang.org/doc/articles/wiki/#tmp_3
You can refactor the "main" function to be "init" to start the code in Google App Engine, and remove the ListenAndServe function; even if you were to change the port number, you won't be able to visit your site at the port.
So this works:
package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Url test: %s!", r.URL.Path[1:])
}

func init() {
    http.HandleFunc("/", handler)
}
Now, our obstacle is to get static files working, and not just a simple text-based string..

A quick search on Stackoverflow returns this code:

package main

import (
    "log"
    "net/http"
)

func main() {
    http.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir("path/to/file"))))
    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

http://stackoverflow.com/a/16672682/1756941
But again, we're dealing with Google App Engine here....
As much as I'd tried to make this work, it doesn't;

package main

import (
    "net/http"
)

func main() {
    http.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir("/files/"))))
}
By now, showing the folder structure would be appropriate, because the code simply does not work. So here it is

App Folder
│   app.yaml
│   index.yaml
│
├───static
│       static.go
│
└───files
        index.html
        photo.jpg
Creating the actual static server ended up being really simple. Using the information learnt from other attempts above, a simple re-write was necessary to complete the first, and final stage of creating a static file server in Go for Google App Engine.

package static

import (
    "net/http"
)

func init() {
    http.HandleFunc("/", static)
}

func static(w http.ResponseWriter, r *http.Request) {
    http.ServeFile(w, r, "files/"+r.URL.Path)
}
So like most other tutorials, you can find the files ready to run a static file server in Go for Google App Engine on GitHub here: https://github.com/extramaster/gae-gostatic