Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building a REST API Service in Go

Building a REST API Service in Go

In this presentation, we build a REST API service for the TodoMVC.com project.

Building REST API services in Go is really about composing many small handlers together. Check out some of the patterns for project structure, build tools, package management, routing, request contexts, authentication / sessions (with jwt), data models, and configuration. I hope after this you'll be on your way to build some awesome REST APIs!

Project: https://github.com/pkieltyka/godo-app

Peter Kieltyka

January 29, 2015
Tweet

Other Decks in Programming

Transcript

  1. Rediscovering Go • 4 years ago, I totally glanced over

    Go after comparing its syntax to my beloved and rich, Ruby • I still like Ruby • But today, Go is absolutely my favorite language for building servers
  2. Pragmatic design Designed as a language to make it easier

    to write highly concurrent server applications
  3. Small, minimal language • Can be learned quite quickly by

    others on the team • In teams, everyone's code looks just like mine, finally. • Readability, top-down • I've had people start becoming effective after a week of working in Go
  4. Concurrency • Concurrency primitives designed into the language • All

    about message passing instead of sharing state • No application-level threads, instead Go providers grooviness which are cooperatively scheduled lightweight routines managed by the Go runtime • M:N scheduler (it does use OS threads under the hood) • Evented network IO • FAST!!! and EFFICIENT!!! goroutine’s initial stack size is 2kb (as of go1.4)
  5. etc.. • Statically typed • Single cross-platform binaries • Great

    dev tools: fmt, vet, cover, GoSublime • Packages
  6. Tip: How to learn Go 1. Do the tour: http://tour.golang.org/

    .. really do it! 2. Read Effective Go: https://golang.org/doc/ effective_go.html 3. Write Go code! 4. Read Effective Go again
  7. Hello World package main import "net/http" func main() { http.ListenAndServe(":4000",

    http.HandlerFunc(HelloWorld)) } func HelloWorld(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) w.Write([]byte("hello world")) }
  8. API Server Anatomy • Routing* • Request context* • Middleware*

    • Models / data persistence • Configuration • Logging • User authentication / sessions* • Responders / serialization • File serving • Error handling * rich ecosystem of libraries for all of these parts
  9. Framework? Libs? • Go is more about the composition of

    many small libraries that connect together with interfaces • Libraries we’re going to use (see Glockfile): • Configuration - github.com/BurntSushi/toml • Auth - github.com/dgrijalva/jwt-go • Http router & request context - github.com/zenazn/goji • Data mapper - upper.io/db
  10. net/http package // ServeHTTP should write reply headers and data

    to the ResponseWriter // and then return. Returning signals that the request is finished // and that the HTTP server can move on to the next request on // the connection. type Handler interface { ServeHTTP(ResponseWriter, *Request) } // A ResponseWriter interface is used by an HTTP handler to // construct an HTTP response. type ResponseWriter interface { Header() Header Write([]byte) (int, error) WriteHeader(int) } type HandlerFunc func(ResponseWriter, *Request) func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r) }
  11. type Request struct { Method string URL *url.URL Proto string

    // "HTTP/1.0" ProtoMajor int // 1 ProtoMinor int // 0 Header Header Body io.ReadCloser ContentLength int64 TransferEncoding []string Close bool Host string Form url.Values PostForm url.Values MultipartForm *multipart.Form Trailer Header RemoteAddr string RequestURI string TLS *tls.ConnectionState } net/http package
  12. Router • aka mux or multiplexer • It’s also of

    http.Handler type • There are many open source routers out there, I like the one from Goji, github.com/zenazn/goji • Idea of building an REST API in Go is really about composing many small handlers together
  13. Router func New() http.Handler { // slightly abbreviated r :=

    web.New() r.Use(middleware.RequestID) r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Get("/", http.RedirectHandler("/app/", 301)) r.Post("/signup", users.SignUp) r.Post("/login", sessions.Login) // Authed router a := web.New() a.Use(middleware.SubRouter) a.Use(godo.App.TokenAuth.Handler) a.Use(sessions.UserContext) a.Get("/todos", todos.Index) // LIST a.Post("/todos", todos.Create) // CREATE a.Get("/todos/:id", todos.Ctx.On(todos.Read)) // READ a.Put("/todos/:id", todos.Ctx.On(todos.Update)) // UPDATE a.Delete("/todos/:id", todos.Ctx.On(todos.Delete)) // DELETE r.Handle("/*", a) // mount the sub-router return r } godo-app/api/api.go
  14. Middleware func StdMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r

    *http.Request) { // before the next handler h.ServeHTTP(w, r) // call the next handler in the chain // after the response }) } func GojiMiddleware(c *web.C, h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // before the next handler c.Env[“obj”] = “hiiii” // putting a k/v pair in the request context h.ServeHTTP(w, r) // call the next handler in the chain // after the response }) }
  15. Authentication • JSON Web Token authentication middleware: • a.Use(godo.App.TokenAuth.Handler) •

    based on github.com/pkieltyka/jwtauth and github.com/ dgrijalva/jwt-go • TokenAuth = jwtauth.New("HS256", []byte(conf.Jwt.Secret), nil) • Token contains base64 encoded values of a header, claims and signature separated by “.” • NOTE: header and claims are in plain text