High Performance

web applications

in go

Andrew Bonventre

@andybons


Hello

package main
import (  "fmt"  "log"  "net/http")
func main() {  http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {    w.Header().Set("Content-Type", "text/plain; charset=utf-8")    fmt.Fprintln(w, "Hello")  })  log.Fatal(http.ListenAndServe(":8080", nil))} 

Huzzah


That’s fine, but...

  • Templates
  • Routing
  • Forms
  • Caching
  • gzip
  • Sessions/Cookies
  • Security (XSRF/XSS)
  • Database ORM
  • ...

we need a Framework!

Revel (http://robfig.github.io/revel/)

frameworks are great...


...


...


...


...but don’t use them.

frameworks


Provide 90% of what you need.


Can really suck to get that last 10%.

THE stdlib


Provides 90% of what you need.

Go’s compositional properties allow for swapping
out or enhancing components to fit your needs.

GZIP

(from the golang-nuts mailing list...)
type gzipResponseWriter struct {
  io.Writer
  http.ResponseWriter
}

func (w gzipResponseWriter) Write(b []byte) (int, error) {
  return w.Writer.Write(b)
}

func makeGzipHandler(fn http.HandlerFunc) http.HandlerFunc {
  return func(w http.ResponseWriter, r *http.Request) {
    if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
      fn(w, r)      return
    }
    w.Header().Set("Content-Encoding", "gzip")
      gz := gzip.NewWriter(w)
      defer gz.Close()
      fn(gzipResponseWriter{Writer: gz, ResponseWriter: w}, r)
    }
}


That’s great, but...


I have to wrap all my handlers?

Seems tedious and inelegant.

Welp, I agree.

But it’s far better than generalizing too early.

Interfaces


type Handler interface {
  ServeHTTP(ResponseWriter, *Request)
}

Just pass in your own Handler
and gzip all requests with
Accept-Encoding: gzip


You can also do some other useful stuff in there...

useful stuff...

func (s *server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
  // Log every request...  log.Printf("%s %s %s %s", req.Proto, req.Method, req.RemoteAddr, req.URL)
// Track request latency to StatHat... defer func(t time.Time) { name := fmt.Sprintf("MyServer[%s][%s]", req.Method, req.URL.Path) stathat.PostEZValue(name, "...", time.Since(t).Seconds()*1000) }(time.Now()) ... gzip, let the muxer do its thing.}

Toolkits

Gorilla (http://www.gorillatoolkit.org/)

thanks

@andybons

High Performance Web Applications in Go

By Andrew Bonventre