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.