How to create simple webservice using GO (golang) on GAE

This tutorial will show how to create simple webservice application using GO on Google Application Engine (GAE), I’m going to cover the following topics:

  1. Creating project in GAE
  2. Creating and testing application locally
  3. Using martini package to simplify service development
  4. Deployment of the services to GAE

First of all, go to Google Developer Console and create new project:

https://console.developers.google.com/project

Screenshot 2015-09-09 09.22.54

Select project name and open advanced options, make sure that you are selecting the proper region you want to use, it is important as if we are going to add SQL Cloud later to our project and the region of the project & SQL Cloud should be the same to work together.

Screenshot 2015-09-09 09.29.28

Give some minutes to Google and you should see the picture as shown below with your project ready to be developed. Copy Project ID (in my case it is tutorial-golang, you will defenitely have different name) to you favourite text editor on your computer, we will need it later when we prepare our first deploy of the application

Screenshot 2015-09-09 09.35.42

Quick note: I am doing this tutorial on Mac but it will be quite similar for Windows and Linux as well.

We need to install Google Application Engine SDK for GO, you can find it here: https://cloud.google.com/appengine/downloads,  select your platform and download, follow installation instructions on the download page. Do not forget to add the PATH to GO SDK to you environment


export PATH=$PATH:/path/to/go_appengine/

Now we are ready to create our “Hello world” application, where we start our journey. Create folder on your computer and the file inside with the name tutorial-webservice.go (or any other you like) and put the following code inside.


package tutorialgolang

import (
 "fmt"
 "net/http"
)

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

func handle(w http.ResponseWriter, r *http.Request) {
 fmt.Fprint(w, "My first GO webservice")
}

We are almost ready to test the app but we need one more thing, the file app.yaml . Create the file with that name in the same folder where you have the file above and put the following text inside:


application: tutorial-golang
version: 1
runtime: go
api_version: go1

handlers:
- url: /.*
 script: _go_app

The tag application should have the same ID as your project ID in Google Developer Console, everything else leave the same as shown above.

Now we are ready to start our application locally to check if it is working, start your favourite terminal application, go to the application folder and type there goapp serve, if you followed this tutorial you should see the following output in the terminal

Screenshot 2015-09-09 10.10.29

Now our app is ready on the address http://localhost:8080, put it in your browser to make sure that our application is working correctly

Screenshot 2015-09-09 10.13.42

Probably you are lazy as me and do not want to invent your own bicycle to create the webservice, that’s why let’s reuse the prepared solution and also learn how we can easily reuse Golang packages created by other people. I like a lot martini, it is a powerful package for quickly writing modular web applications/services in Golang, as they describe themselves.

So let’s go back to command line and our app folder (use Ctrl-C if the previously running service is still running there) and simply write there:

goapp get github.com/go-martini/martini

This command will download and install the package locally and later it will be used also when we will deploy application to GAE (Google Application Engine). That’s it, the magic is done!

Now let’s change our application and use martini there (check more about martini package here: https://github.com/go-martini/martini)


package tutorialgolang

import (
 "net/http"
 "github.com/go-martini/martini"
)

func init() {
 m := martini.Classic()
 m.Get("/", func() string {
 return "My first GO webservice (using martini package)" 
 })
 http.Handle("/", m)
}

Now start the app in the terminal with goapp serve again and check result in your browser. If everything is fine let’s do another magic, let’s move our application to google app engine. It is more than easy, just type in the terminal in the folder of your app (make sure before that the correct application name is set inside of app.yaml):

goapp deploy 

You should see the similar output in your terminal window as below

Screenshot 2015-09-09 10.35.45

Now it is time to check our project in google developer console, go to the menu Compute->App Engine->Dashboard as shown below and you should have similar picture. Click on the link in the right top corner to see as your application is actually working.

Screenshot 2015-09-09 10.40.45

 

Now let’s make our webservice little bit more interesting, let’s create 2 webservices /math/sum  and /math/multiply to perform appropriate math operations, let’s create summing as GET request and multiplying as POST request, the code will look this way


package tutorialgolang
import (
  "encoding/json"
  "github.com/go-martini/martini"
  "github.com/martini-contrib/binding"
  "io"
  "net/http"
  "strconv"
)
type SuccessResponse struct {
  Status string `json:"status"`
  Result string `json:"result"`
  Expression string `json:"expression"`
}
type MultiplyForm struct {
  Parm1 string `form:"parm1" binding:"required"`
  Parm2 string `form:"parm2" binding:"required"`
}
func init() {
  m := martini.Classic()
  m.Get("/", func() string {
    return "My first GO webservice: use /math/sum as GET or /math/multiply as POST"
  })
  m.Group("/math", func(r martini.Router) {
    r.Get("/sum/:parm1/:parm2", Sum)
    r.Post("/multiply", binding.Bind(MultiplyForm{}), Multiply)
  })
  m.NotFound(func(w http.ResponseWriter) {
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    w.WriteHeader(http.StatusNotFound)
    io.WriteString(w, "{\"status\":\"error\",\"msg\":\"Error when converting to JSON \"}")
  })
  http.Handle("/", m)
}

func PrepareSuccessReply(w http.ResponseWriter, preparedStruct interface{}) {
  b, err := json.Marshal(preparedStruct)
  if err == nil {
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    w.WriteHeader(http.StatusOK)
    io.WriteString(w, string(b[:]))
  } else {
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    w.WriteHeader(http.StatusOK)
    io.WriteString(w, "{\"status\":\"error\",\"msg\":\"Error when converting to JSON \"}")
  }
}

func Sum(w http.ResponseWriter, params martini.Params, req *http.Request) {
  var sResponse SuccessResponse
  parm1, _ := strconv.Atoi(params["parm1"])
  parm2, _ := strconv.Atoi(params["parm2"])
  result := strconv.Itoa(parm1 + parm2)
  sResponse.Status = "success"
  sResponse.Result = result
  sResponse.Expression = params["parm1"] + " + " + params["parm2"] + " = " + result
  PrepareSuccessReply(w, sResponse)
}

func Multiply(w http.ResponseWriter, mForm MultiplyForm, req *http.Request) {
  var sResponse SuccessResponse
  parm1, _ := strconv.Atoi(mForm.Parm1)
  parm2, _ := strconv.Atoi(mForm.Parm2)
  result := strconv.Itoa(parm1 * parm2)
  sResponse.Status = "success"
  sResponse.Result = result
  sResponse.Expression = mForm.Parm1 + " * " + mForm.Parm2 + " = " + result
  PrepareSuccessReply(w, sResponse)
}

 

I use another additional binding package for martini to simplify processing of the post data (install with “goapp get github.com/martini-contrib/binding“), transformation from GO structs to JSON is golang standard (package “encoding/json“), everything else looks more or less self explanatory.

Do not forget to deploy the webservice to GAE: goapp deploy

Below is curl for testing the service of this tutorial:


curl https://tutorial-golang.appspot.com/math/sum/23/54
curl --data "parm1=7&parm2=11"  https://tutorial-golang.appspot.com/math/multiply

Stay tuned, there will be one more additional part explaining how to work with GAE Cloud SQL from GO and how to store your code in GAE git repository.

If you want to use Sublime Text to develop with GO for GAE, check these tips.

Happy coding!

, , , , , , , , , ,

  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: