RESTful Web Applications
with Google Go
Frank Müller
Oldenburg / Germany
Released Summer 1965
Software Engineer
Author
!
mue@tideland.biz
blog.tideland.biz
@themu...
Goals
• Usage of HTTP / HTTPS

• Multiplexing based on path containing functional
domain, resource, and possible resource ...
Google Go
Go HTTP Package
• Simple

• Types implementing http.Handler interface or
functions with a defined signature for handling

•...
Go HTTP Package - Handler
type MyHandler struct{}
!
// Implementing http.Handler interface.
func (mh *MyHandler) ServeHTTP...
Go HTTP Package - Main
!
func main() {
	 // Register handler for path.
	 http.Handle(”/myHandler”, &MyHandler{})
!
	 // St...
❝Simple tasks can be done using the
standard library, but own powerful
packages are easy to create.
–Gopher
RESTful Web Multiplexer
Multiplexer
• Go default uses a prefix based pattern

• Our RWM maps based on domain and resource

• Request and response w...
Multiplexer - Type
// RESTfulWebMultiplexer is our own multiplexer.
type RESTfulWebMultiplexer struct {
	 mapping domains
...
Multiplexer - Interface Method
// ServeHTTP implements the handler interface.
func (mux * RESTfulWebMultiplexer) ServeHTTP...
Multiplexer - Main
!
func main() {
	 // Create multiplexer and add handlers.
	 mux := NewRESTfulWebMultiplexer()
!
	 mux.A...
❝Own multiplexers make HTTP server
more flexible.
–Gopher
Multiplexer - Domains
// domains maps domains to their resources.
type domains map[string]resources
!
// handle retrieves ...
Multiplexer - Resources
// resources maps resources to their handler lists.
type resources map[string]handlers
!
// handle...
Multiplexer - Handlers
// handlers chains all handlers for one resource.
type handlers []ResourceHandler
!
// handle lets ...
❝Use my simple type system for small
types with useful methods.
–Gopher
Handle your resources
Resource Handler
• Basic interface for initialization and read operation

• Additional interfaces for create, update, and ...
Resource Handler - Base Interface
// ResourceHandler defines the base interface. It handles the
// HTTP GET method with Rea...
Resource Handler - Create Interface
// CreateResourceHandler defines the interface to additionally
// handle the HTTP POST ...
Resource Handler - Dispatch
// dispatch maps HTTP methods to handler function calls.
func (mux *RESTfulWebMultiplexer) dis...
❝Small interfaces and type assertions
are a powerful combination.
–Gopher
See the context
Context
• Simple wrapper for request and response

• Provides information about domain, resource and id

• Also provides i...
Context - Type
// Context encapsulates all needed data for handling a request.
type Context struct {
	 Mux	 	 	 	 	 	 	 	 ...
Context - Simple Request Analysis
// accepts checks if the requestor accepts a content type.
func (ctx *Context) accepts(c...
Context - Typical Operations
// Redirect to a domain, resource and resource id (optional).
func (ctx *Context) Redirect(
	...
❝Public fields are not evil as long as
the data is not shared.
–Gopher
JSON Marshaling
• Go likes JSON

• Really! (scnr)

• Automatically, controlled, and manually
JSON - Standard
// Public fields will be marshaled.
type Demo struct {
	 FieldA	 string
	 FieldB	 int
	 FieldC		 *OtherStru...
JSON - Controlled
// Control with field tags.
type AnotherDemo struct {
	 FieldA	 string		 `json:”-”`	 	 	 	 // Ignore.
	 F...
JSON - Manually
// User has to care for it.
type StillADemo struct {
	 fieldA	string
	 fieldB	int
}
!
// MarshalJSON impleme...
JSON - Integrate in Context
func (ctx *Context) RespondJSON(
	 data interface{}, html bool) error {
	 b, err := json.Marsh...
❝My standard library provides powerful
encoding packages, also for XML,
CSV, ASN.1, etc.
–Gopher
Scenario
Tags by Interest
Browser
Stat
Handler
Content
Handler
Tag
Handler
Content
Backend
Stat
Backend
DB
GET /content/page/4711
G...
Stat Handler
func (h *StatHandler) Read(ctx *rwm.Context) (bool, error) {
	 if ctx.ResourceId != ”” {
	 	 // Backend handl...
Content Handler
func (h *ContentHandler) Read(
	 ctx *rwm.Context) (bool, error) {
	 var page *Page
	 if ctx.ResourceId !=...
Tag Handler
func (h *StatHandler) Read(ctx *rwm.Context) (bool, error) {
	 var err error
	 switch ctx.ResourceId {
	 case ...
❝Enjoy Go, it’s lightweight, simple and
very productive.
–Gopher
❝ Zitat hier eingeben.
–Christian BauerImages
123RF

iStockphoto

Own Sources
RESTful Web Applications with Google Go
Upcoming SlideShare
Loading in …5
×

RESTful Web Applications with Google Go

1,335 views

Published on

Published in: Software, Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,335
On SlideShare
0
From Embeds
0
Number of Embeds
9
Actions
Shares
0
Downloads
19
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

RESTful Web Applications with Google Go

  1. 1. RESTful Web Applications with Google Go
  2. 2. Frank Müller Oldenburg / Germany Released Summer 1965 Software Engineer Author ! mue@tideland.biz blog.tideland.biz @themue github.com/tideland
  3. 3. Goals • Usage of HTTP / HTTPS • Multiplexing based on path containing functional domain, resource, and possible resource id • List of multiple handles to support generic tasks like authentication and authorization • Mapping of HTTP methods to CRUD operations • Major data is JSON, but also XML and templates
  4. 4. Google Go
  5. 5. Go HTTP Package • Simple • Types implementing http.Handler interface or functions with a defined signature for handling • Integrated server able to handle HTTP and HTTPS • Not very convenient
  6. 6. Go HTTP Package - Handler type MyHandler struct{} ! // Implementing http.Handler interface. func (mh *MyHandler) ServeHTTP( w http.ResponseWriter, r *http.Request) { w.Header().Set(”Content-Type”, ”text/plain”) w.WriteHeader(http.StatusOK) fmt.Fprintln(w, ”Hello, Go User Group!”) }
  7. 7. Go HTTP Package - Main ! func main() { // Register handler for path. http.Handle(”/myHandler”, &MyHandler{}) ! // Start server on port 8080. log.Fatal(http.ListenAndServe(”:8080”, nil)) }
  8. 8. ❝Simple tasks can be done using the standard library, but own powerful packages are easy to create. –Gopher
  9. 9. RESTful Web Multiplexer
  10. 10. Multiplexer • Go default uses a prefix based pattern • Our RWM maps based on domain and resource • Request and response wrapped into convenient context • Fallback to a default handler
  11. 11. Multiplexer - Type // RESTfulWebMultiplexer is our own multiplexer. type RESTfulWebMultiplexer struct { mapping domains … } ! // AddHandler adds a handler based on domain and resource. func (mux * RESTfulWebMultiplexer) AddHandler( domain, resource string, h ResourceHandler) error { … }
  12. 12. Multiplexer - Interface Method // ServeHTTP implements the handler interface. func (mux * RESTfulWebMultiplexer) ServeHTTP( w http.ResponseWriter, r *http.Request) { ctx := newContext(mux, w, r) if err := mux.mapping.handle(ctx); err != nil { … } }
  13. 13. Multiplexer - Main ! func main() { // Create multiplexer and add handlers. mux := NewRESTfulWebMultiplexer() ! mux.AddHandler(”content”, ”blog”, NewBlogHandler()) … ! // Start server with our multiplexer on port 8080. log.Fatal(http.ListenAndServe(”:8080”, mux)) }
  14. 14. ❝Own multiplexers make HTTP server more flexible. –Gopher
  15. 15. Multiplexer - Domains // domains maps domains to their resources. type domains map[string]resources ! // handle retrieves the resources for the context domain and // lets them handle the context. func (d domains) handle( ctx *RequestContext) error { resources, ok := d[ctx.Domain] if !ok { resources = d[ctx.Mux.DefaultDomain()] } // Continue handling. return resources.handle(ctx) }
  16. 16. Multiplexer - Resources // resources maps resources to their handler lists. type resources map[string]handlers ! // handle retrieves the handlers for the context resource and lets // them handle the context. func (r resources) handle( ctx *RequestContext) error { handlers, ok := r[ctx.Resource] if !ok { handlers = r[ctx.Mux.DefaultResource(ctx.Domain)] } // Continue handling. return handlers.handle(ctx) }
  17. 17. Multiplexer - Handlers // handlers chains all handlers for one resource. type handlers []ResourceHandler ! // handle lets all handlers handle the context. func (h handlers) handle( ctx *RequestContext) error { for _, handler := range h { ok, err := ctx.Mux.dispatch(ctx, handler) if err != nil { return err } // Handler tells to stop, but w/o error. if !ok { return nil } } return nil }
  18. 18. ❝Use my simple type system for small types with useful methods. –Gopher
  19. 19. Handle your resources
  20. 20. Resource Handler • Basic interface for initialization and read operation • Additional interfaces for create, update, and delete operations • Dispatcher to map HTTP methods
  21. 21. Resource Handler - Base Interface // ResourceHandler defines the base interface. It handles the // HTTP GET method with Read(). type ResourceHandler interface { // Init is called after registration of the handler. Init(domain, resource string) error ! // Read is called if the HTTP method is GET. Read(ctx *Context) (bool, error) }
  22. 22. Resource Handler - Create Interface // CreateResourceHandler defines the interface to additionally // handle the HTTP POST with Create(). type CreateResourceHandler interface { // Create is called if the HTTP method is POST. Create(ctx *Context) (bool, error) }
  23. 23. Resource Handler - Dispatch // dispatch maps HTTP methods to handler function calls. func (mux *RESTfulWebMultiplexer) dispatch( ctx *Context, h ResourceHandler) (bool, error) { switch ctx.Request.Method { case ”GET”: return h.Read(ctx) case ”POST”: if ch, ok := h.(CreateResourceHandler); ok { return ch.Create(ctx) } return false, errors.New(”handler cannot process POST”) case … } return false, errors.New(”invalid HTTP method”) }
  24. 24. ❝Small interfaces and type assertions are a powerful combination. –Gopher
  25. 25. See the context
  26. 26. Context • Simple wrapper for request and response • Provides information about domain, resource and id • Also provides information about stuff like accepted content types and languages • Allows simpler reading and writing of JSON etc.
  27. 27. Context - Type // Context encapsulates all needed data for handling a request. type Context struct { Mux *RESTfulWebMultiplexer Writer http.ResponseWriter Request *http.Request Domain, Resource, ResourceId string } ! // newContext creates a new context and parses the URL path. func newContext( mux *RESTfulWebMultiplexer, w http.ResponseWriter, r *http.Request) *Context { … }
  28. 28. Context - Simple Request Analysis // accepts checks if the requestor accepts a content type. func (ctx *Context) accepts(ct string) bool { accept := ctx.Request.Header.Get(”Accept”) return strings.Contains(accept, ct) } ! // AcceptsJSON checks if the requestor accepts JSON as // a content type. func (ctx *Context) AcceptsJSON() bool { return ctx.accepts(”application/json”) }
  29. 29. Context - Typical Operations // Redirect to a domain, resource and resource id (optional). func (ctx *Context) Redirect( domain, resource, resourceId string) { url := ctx.Mux.BasePath() + domain + ”/” + resource if resourceId != ”” { url += ”/” + resourceId } ctx.Writer.Header().Set(”Location”, url) ctx.Writer.WriteHeader(http.StatusMovedPermanently) }
  30. 30. ❝Public fields are not evil as long as the data is not shared. –Gopher
  31. 31. JSON Marshaling • Go likes JSON • Really! (scnr) • Automatically, controlled, and manually
  32. 32. JSON - Standard // Public fields will be marshaled. type Demo struct { FieldA string FieldB int FieldC *OtherStruct fieldX bool // No, you won’t see me. } ! demo := &demo{ … } ! // b contains the marshaled demo struct as []byte. b, err := json.Marshal(demo)
  33. 33. JSON - Controlled // Control with field tags. type AnotherDemo struct { FieldA string `json:”-”` // Ignore. FieldB int `json:”OtherName”` // Change name. FieldC float64 `json:”,string”` // As string. FieldD bool `json:”,omitempty”` // Ignore if empty. FieldE string // As usual. fieldX int // Still ignored. }
  34. 34. JSON - Manually // User has to care for it. type StillADemo struct { fieldA string fieldB int } ! // MarshalJSON implements the Marshaler interface. func (d *StillADemo) MarshalJSON() ([]byte, error) { format := `{”First”: %q, ”Second”: %d}` json := fmt.Sprintf(format, d.fieldA, d.fieldB) return []byte(json), nil }
  35. 35. JSON - Integrate in Context func (ctx *Context) RespondJSON( data interface{}, html bool) error { b, err := json.Marshal(data) if err != nil { return fmt.Errorf(”cannot respond JSON: %v”, err) } if html { var buf bytes.Buffer json.HTMLEscape(&buf, b) b = buf.Bytes() } ctx.Writer.Header().Set(”Content-Type”, ”application/json”) _, err = ctx.Writer.Write(b) return err }
  36. 36. ❝My standard library provides powerful encoding packages, also for XML, CSV, ASN.1, etc. –Gopher
  37. 37. Scenario
  38. 38. Tags by Interest Browser Stat Handler Content Handler Tag Handler Content Backend Stat Backend DB GET /content/page/4711 GET /content/tags/interest Goroutines Async Update Page Request gets HTML JS Request gets JSON
  39. 39. Stat Handler func (h *StatHandler) Read(ctx *rwm.Context) (bool, error) { if ctx.ResourceId != ”” { // Backend handles update in background. statBackend.UpdatePage(ctx.ResourceId) } return true, nil }
  40. 40. Content Handler func (h *ContentHandler) Read( ctx *rwm.Context) (bool, error) { var page *Page if ctx.ResourceId != ”” { page = contentBackend.Page(ctx.ResourceId) } else { page = contentBackend.Index() } if err := ctx.RespondTemplate(h.template, page); err != nil { return false, err } return true, nil }
  41. 41. Tag Handler func (h *StatHandler) Read(ctx *rwm.Context) (bool, error) { var err error switch ctx.ResourceId { case ”interest”: tags := statBackend.TagsByInterest() if ctx.AcceptsJSON() { err = ctx.RespondJSON(tags, true) } else if ctx.AcceptsXML() { err = ctx.RespondXML(tags) } case … } … }
  42. 42. ❝Enjoy Go, it’s lightweight, simple and very productive. –Gopher
  43. 43. ❝ Zitat hier eingeben. –Christian BauerImages 123RF iStockphoto Own Sources

×