Go for a bit of REST and JSON

I’ve been playing around with Go. Here’s a quick skeleton to start up a REST microservice, using the GoRest framework, and using the Go-Uuid library to generate a UUID.

You’ll need to download the imports.

$ go get code.google.com/p/gorest
$ go get code.google.com/p/go-uuid/uuid

Let’s create our response type in src/Message.go.

package main
 
import "code.google.com/p/go-uuid/uuid"
 
// Return type.
//
// Note that we're using annotations to correctly capitalise the fields when serializing, because
// Go requires the fields to be exportable (start with an uppercase letter) to serialize them.
type Message struct {
	Message    string `json:"message"`
	Identifier string `json:"identifier"`
}
 
// Constructor.
//
// Creates a new message with the specified text and a new UUID.
//
// Param: newMessage The message text.
//
// Returns: A Message object with the specified text and a uuid identifier.
func newMessage(newMessage string) Message {
	return Message{Identifier: uuid.New(), Message: newMessage}
}

import "code.google.com/p/go-uuid/uuid"

// Return type.
//
// Note that we’re using annotations to correctly capitalise the fields when serializing, because
// Go requires the fields to be exportable (start with an uppercase letter) to serialize them.
type Message struct {
Message string `json:"message"`
Identifier string `json:"identifier"`
}

// Constructor.
//
// Creates a new message with the specified text and a new UUID.
//
// Param: newMessage The message text.
//
// Returns: A Message object with the specified text and a uuid identifier.
func newMessage(newMessage string) Message {
return Message{Identifier: uuid.New(), Message: newMessage}
}

Next we need to configure the GoRest framework – save the following into src/MessageService.go.

package main
 
import (
	"code.google.com/p/gorest"
	"fmt"
	"time"
)
 
// Service configuration for the GoRest framework.
//
// We only add a single GET endpoint to demonstrate wiring it up.
type MessageService struct {
	// Service configuration
	gorest.RestService `root:"/" consumes:"application/json" produces:"application/json"`
 
	// URL handler added here. The name must match but be initial lowercase here, but uppercase for the function.
	getMessage gorest.EndPoint `method:"GET" path:"/" output:"Message"`
}
 
// Service handler.
//
// Name matches that in the service configuration struct above except it starts with an uppercase character.
//
// Returns a Message which is serialised to json.
func (serv MessageService) GetMessage() Message {
	fmt.Printf("In AMessage\n")
	return <-generateMessage()
}
 
// Worker function.
//
// Returns a channel upon which you can wait for the response to appear upon.
func generateMessage() <-chan Message {
	out := make(chan Message)
 
	// Gofunc which simulates work by sleeping for a second
	go func() {
		time.Sleep(1 * time.Second)
		out <- newMessage("Hello")
		close(out)
	}()
 
	return out
}

import (
"code.google.com/p/gorest"
"fmt"
"time"
)

// Service configuration for the GoRest framework.
//
// We only add a single GET endpoint to demonstrate wiring it up.
type MessageService struct {
// Service configuration
gorest.RestService `root:"/" consumes:"application/json" produces:"application/json"`

// URL handler added here. The name must match but be initial lowercase here, but uppercase for the function.
getMessage gorest.EndPoint `method:"GET" path:"/" output:"Message"`
}

// Service handler.
//
// Name matches that in the service configuration struct above except it starts with an uppercase character.
//
// Returns a Message which is serialised to json.
func (serv MessageService) GetMessage() Message {
fmt.Printf("In AMessage\n")
return <-generateMessage()
}

// Worker function.
//
// Returns a channel upon which you can wait for the response to appear upon.
func generateMessage() <-chan Message {
out := make(chan Message)

// Gofunc which simulates work by sleeping for a second
go func() {
time.Sleep(1 * time.Second)
out <- newMessage("Hello")
close(out)
}()

return out
}

And finally we have to wire it altogether and put in an entry function – put this in src/MainModule.go

package main
 
// You'll need to
//   go get code.google.com/p/gorest
//   go get code.google.com/p/go-uuid/uuid
// to get download the imports first
 
import (
	"code.google.com/p/gorest"
	"net/http"
)
 
// Program entry point.
//
// Registers the services with the GoRest framework, and starts the HTTP server
// on the specified port.
func main() {
	gorest.RegisterService(new(MessageService))
	http.Handle("/", gorest.Handle())
	http.ListenAndServe(":8787", nil)
}

// You’ll need to
// go get code.google.com/p/gorest
// go get code.google.com/p/go-uuid/uuid
// to get download the imports first

import (
"code.google.com/p/gorest"
"net/http"
)

// Program entry point.
//
// Registers the services with the GoRest framework, and starts the HTTP server
// on the specified port.
func main() {
gorest.RegisterService(new(MessageService))
http.Handle("/", gorest.Handle())
http.ListenAndServe(":8787", nil)
}

With that all in place, I would format the code (using the built-in Go code formatter) and then run it up:-

$ go fmt src/*
$ go run src/*
2015/01/22 20:12:44 All EndPoints for service [ MessageService ] , registered under root path:  /
2015/01/22 20:12:44 Registerd service: MessageService  endpoint: GET

which you can then test in another window (I pipe the output via Python’s JSON tool to pretty-print it)

$ curl localhost:8787/ | python -m json.tool
{
    "identifier": "86541463-0116-4778-9470-ddd846ee649b",
    "message": "Hello"
}

Additional: If you want to build a static binary:-

$ go build src/*
$ ./MainModule
2015/01/22 20:17:16 All EndPoints for service [ MessageService ] , registered under root path:  /
2015/01/22 20:17:16 Registerd service: MessageService  endpoint: GET

Code available in Git at https://bitbucket.org/AndrewGorton/simplegomicroservice.

This is my personal blog - all views are my own.

Tagged with: , , ,