Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Writing HTTP Middleware In Go

2,608 views

Published on

Slide for the talk titled "Writing HTTP Middleware In Go" at GopherCon India 2016

Published in: Technology
  • Be the first to comment

Writing HTTP Middleware In Go

  1. 1. Writing HTTP Middleware In Go Shiju Varghese GopherCon India 2016
  2. 2. Agenda • Introduction to HTTP Middleware • Writing HTTP Middleware with Negroni
  3. 3. HTTP Handlers ! ! ! ! ! ! Handlers are responsible for writing headers and bodies ! into HTTP responses. ! ! // ServeHTTP should write reply headers and data // to the ResponseWriter and then return. ! type Handler interface { ServeHTTP(ResponseWriter, *Request) }
  4. 4. HTTP Middleware • Pluggable and self-contained piece of code that wraps web application handlers.! • Components that work as another layer in the request handling cycle, which can execute some logic before or after executing your HTTP application handlers.! • Great for implementing cross-cutting concerns: Authentication, authorization, caching, logging, etc. !
  5. 5. Using StripPrefix to Wraps http.FileServer handler package main ! import ( "net/http" ) ! func main() { // To serve a directory on disk under an alternate URL // path (/public/), use StripPrefix to modify the request // URL's path before the FileServer sees it: ! fs := http.FileServer(http.Dir("public")) http.Handle("/public/", http.StripPrefix("/public/", fs)) }
  6. 6. func StripPrefix(prefix string, h Handler) Handler { if prefix == "" { return h } return HandlerFunc(func(w ResponseWriter, r *Request) { if p := strings.TrimPrefix(r.URL.Path, prefix); len(p) < len(r.URL.Path) { r.URL.Path = p h.ServeHTTP(w, r) } else { NotFound(w, r) } }) } StripPrefix Function
  7. 7. Pattern for Writing HTTP Middleware . func middlewareHandler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Our middleware logic goes here before // executing application handler next.ServeHTTP(w, r) // Our middleware logic goes here after // executing application handler }) }
  8. 8. Writing a Logging Middleware func loggingHandler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ! // Before executing the handler ! start := time.Now() log.Printf("Started %s %s", r.Method, r.URL.Path) next.ServeHTTP(w, r) ! // After executing the handler ! log.Printf("Completed %s in %v", r.URL.Path, time.Since(start)) }) } • Parameter of type http.Handler! • Returns http.Handler type
  9. 9. ! ! func index(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome!") } func about(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "About") } func main() { http.Handle("/", loggingHandler(http.HandlerFunc(index))) http.Handle("/about", loggingHandler(http.HandlerFunc(about))) ! server := &http.Server{ Addr: ":3000", } server.ListenAndServe() } Using the Logging Middleware
  10. 10. Middleware Chaining http.Handle("/", middlewareFirst(middlewareSecond(loggingHandler( http.HandlerFunc(index)))))
  11. 11. Using HTTP Middleware with Negroni Package
  12. 12. Install Negroni:! $ go get github.com/codegangsta/negroni! Import Negroni package:! import "github.com/codegangsta/negroni"
  13. 13. // Handler handler is an interface that objects // can implement to be registered to serve as middleware // in the Negroni middleware stack. // ServeHTTP should yield to the next middleware // in the chain by invoking the next http.HandlerFunc // passed in. // // If the Handler writes to the ResponseWriter, the next http.HandlerFunc should not be invoked. type Handler interface { ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) } ! // HandlerFunc is an adapter to allow the use of // ordinary functions as Negroni handlers. type HandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) ! func (h HandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { h(rw, r, next) }
  14. 14. Writing HTTP Middleware with Negroni func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { // logic before executing the next handler next(rw, r) // logic after executing the next handler }
  15. 15. Mapping Middleware Chaining with Negroni func main() { mux := http.NewServeMux() // map your routes here n := negroni.New() // You can map it to the handler chain with the Use function: n.Use(negroni.HandlerFunc(MyMiddleware)) n.UseHandler(mux) server := &http.Server{ Addr: ":8080", Handler: n, } server.ListenAndServe() }
  16. 16. Register Middleware Handlers for Specific Routes router := mux.NewRouter() adminRoutes := mux.NewRouter() ! // add admin routes here .. . ! // Add route specific Middleware to “/admin” route router.Handle("/admin", negroni.New( Middleware1, Middleware2, negroni.Wrap(adminRoutes), ))
  17. 17. Applying an Authentication Middleware into Specific Routes
  18. 18. // Middleware for validating JWT tokens func Authorize(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { // validate the token token, err := jwt.ParseFromRequest(r, func(token *jwt.Token) (interface{}, error) { ! // Verify the token with public key, which is the counter part of private key return verifyKey, nil }) ! if err != nil { switch err.(type) { ! case *jwt.ValidationError: // JWT validation error vErr := err.(*jwt.ValidationError) ! switch vErr.Errors { case jwt.ValidationErrorExpired: //JWT expired DisplayAppError(w, err, "Access Token is expired, get a new Token", 401) return ! default: DisplayAppError(w, err, "Error while parsing the Access Token!", 500) return } ! default: DisplayAppError(w, err, "Error while parsing Access Token!", 500) return } ! } if token.Valid { next(w, r) } else { DisplayAppError(w, err, "Invalid Access Token", 401) ! } }
  19. 19. // Routes for “/users” path func SetUserRoutes(router *mux.Router) *mux.Router { router.HandleFunc("/users/register", controllers.Register).Methods("POST") router.HandleFunc("/users/login", controllers.Login).Methods("POST") return router } ! // Routes for “/tasks” path func SetTaskRoutes(router *mux.Router) *mux.Router { taskRouter := mux.NewRouter() taskRouter.HandleFunc("/tasks", controllers.CreateTask).Methods("POST") taskRouter.HandleFunc("/tasks/{id}", controllers.UpdateTask).Methods(“PUT”) .. . ! // Apply Authorize middleware into “/tasks” path ! router.PathPrefix("/tasks").Handler(negroni.New( negroni.HandlerFunc(Authorize), negroni.Wrap(taskRouter), )) return router }
  20. 20. THANKS Shiju Varghese! gophermonk@gmail.com https://medium.com/@shijuvar https://github.com/shijuvar

×