I am starting to port Udacity course CS253 Web Development from python to Go. This seems to be a good way to get into Go while covering App Engine SDK.





The python repository.

The Go repository.

Starting with Go and App Engine

If you have any comments please do so, I will be more than happy to update and improve my code and learn to better develop in Go code.

To start with Go and App Engine there are a lot of resources out there. Here are the ones I used the most:



Installation and commands

Go App Engine SDK does not have a GoogleAppEngineLauncher (like for python). So you will have to launch and deploy your application via the command line.

To run my application I do as follows:

~/google_appengine/dev_appserver.py udacity.cs253.go/

~

PATH

~/google_appengine/appcfg.py update udacity.cs253.go

Unit 1: Hello World and Handlers

I put the google_appengine sdk in. I had some troubles when I put the Go GAE scripts in myas I also have the python GAE SDK, I think it conflicts. This is the reason why I am explicit when runningTo deploy my application I do as follows:udacity.cs253.go is the name of my application.

So I started with Unit 1. Here is what the python code of my main.py looks like in python, 3 handlers a simple hello world handler and 2 handlers date and thanks that comunicate through a Form:



import webapp2

import re

from unit1 import *

class MainHandler(webapp2.RequestHandler):

def get(self):

self.response.out.write('Hello Udacity!')

app = webapp2.WSGIApplication([('/', MainHandler),

('/unit1/date',DateHandler),

('/unit1/thanks',ThanksHandler)],debug=True)



package main

import (

"fmt"

"net/http"

"appengine"

"unit1"

)

func init(){

http.HandleFunc("/", mainHandler)

http.HandleFunc("/unit1/date", unit1.DateHandler)

http.HandleFunc("/unit1/thanks", unit1.ThanksHandler)

}

func mainHandler(w http.ResponseWriter, r *http.Request){

c := appengine.NewContext(r)

c.Infof("Requested URL: %v", r.URL)

fmt.Fprint(w,"hello Udacity with Go!")

}



c.Infof("Requested URL: %v", r.URL)

2013/06/09 19:38:14 INFO: Requested URL: /

import (

"fmt"

"net/http"

"appengine"

"unit1"

"unit2"

"unit3"

)



Unit 1: Date and Thanks Handlers

And here is what mylooks like after some work.I am using the context interface to log in the console.This will display on your console as follows:Also, I decided to do a package for every unit so that I can simply import each package like this:I won't be externalizing this so there is no need to do theorganization for packages.

The /unit1/date url has a simple form with month, day and year inputs and a submit button.

In Jinja this is the template that was used for the course:





<form method="post">

What is your birthday?

<br>

<label>Month

<input name="month" value="%(month)s">

</label>

<label>Day

<input name="day" value="%(day)s">

</label>

<label>Year

<input name="year" value="%(year)s">

</label>

<div style="color:red">%(error)s</div>

<br>

<br>

<input type="submit">

</form>

<html>

<body>

<form method="post">

What is your birthday?

<br>

<label>Month

<input name="month" value="{{.Month}}">

</label>

<label>Day

<input name="day" value="{{.Day}}">

</label>

<label>Year

<input name="year" value="{{.Year}}">

</label>

<div style="color:red">{{.Error}}</div>

<br>

<br>

<input type="submit">

</form>

</body>

</html>

Templates in Go work with curly braces.

Notice that I had to add the html, and body tags to this template else it would display an error as the html is not a valid web page.

type Date struct{

Month string

Day string

Year string

Error string

}

func DateHandler(w http.ResponseWriter, r *http.Request){

if r.Method == "GET" {

date := Date{

Month: "",

Day: "",

Year: "",

}

if err := dateTemplate.Execute(w,date); err != nil{

http.Error(w, err.Error(), http.StatusInternalServerError)

return

}

} else if r.Method == "POST"{

// ...

}

}



var dateTemplate = template.Must(template.New("MyDate").Parse(dateHTML))



Post and Get methods

Go handles templates in the html package, so there is no need to install jinja or any template API, that is a great plus. Here is my resulting template for this part of the course.Some notes about this:This template works with its corresponding structure. I made a structurefor all the fields present in the html form:To render the form I now do the following:whereis the html template defined above andis defined as follows and uses thepackage:

To handle Post and Get methods in python you would have a class for each handler and a Post and Get method as follows:





class DateHandler(webapp2.RequestHandler):

def get(self):

# to something



def post(self):

# do something else

func DateHandler(w http.ResponseWriter, r *http.Request){

c := appengine.NewContext(r)

c.Infof("cs253: Requested URL: %v", r.URL)

c.Infof("cs253: Http METHOD: %v",r.Method)

if r.Method == "GET" {

// do something

} else if r.Method == "POST"{

// do something else

}else{

// this is an error

}

}

Extracting information from the Form

In Go you don't have classes and each handler is a function itself. Right now I am testing the http.Request Method to differentiate each case:

On the post method we will extract the form information, this is a very common case.

In python you would get the information as follows:





def post(self):

user_month = self.request.get('month')

user_day = self.request.get('day')

user_year = self.request.get('year')



month = valid_month(user_month)

day = valid_day(user_day)

year = valid_year(user_year)

if not(month and day and year):

self.write_form("That's an error!",user_month,user_day,user_year)

else:

self.redirect('/unit1/thanks')

func DateHandler(w http.ResponseWriter, r *http.Request){

c := appengine.NewContext(r)

c.Infof("cs253: Requested URL: %v", r.URL)

c.Infof("cs253: Http METHOD: %v",r.Method)

if r.Method == "GET" {

// the GET method

} else if r.Method == "POST"{

d := Date{

Month: validMonth(r.FormValue("month")),

Day: validDay(r.FormValue("day")),

Year: validYear(r.FormValue("year")),

}

if d.Day == "" || d.Month == "" || d.Year == ""{

d.Error = "That's an error!"

if err := dateTemplate.Execute(w,d); err != nil{

http.Error(w, err.Error(), http.StatusInternalServerError)

return

}

}

http.Redirect(w,r, "/unit1/thanks", http.StatusFound)

}

}



Santiaago

In Go this is how I handled this:To get the values I use the FormValue method on the http.Request. Then just execute the template with the structure.This covers the first CS253 Unit. Next time will be about Unit 2.