A Case for Middleware

What is middleware?

Anything that happens between your app receiving a request and that request hitting it's controller/handler.

controller

request

response

request ID

auth

throttle

router := mux.NewRouter() //link routes to handlers
router.HandleFunc("/alarms", listAlarms).Methods("GET")
router.HandleFunc("/persons/{id}",  updatePerson).Methods("PUT")

http.Handle("/", router) //listen for http requests

func listAlarms(res http.ResponseWriter, req *http.Request){
	requestIDHelper(req)
	if !isAuthorized(req) {
		res.WriteHeader(403)
		return
	}
	if needsThrottle(req){
		res.WriteHeader(429)
		return
	}
	// - Business Logic - 
	// - Write Response -
}

func updatePerson(res http.ResponseWriter, req *http.Request){
	requestIDHelper(req)
	if !isAuthorized(req) {
		res.WriteHeader(403)
		return
	}
	if needsThrottle(req){
		res.WriteHeader(429)
		return
	}
	// - Business Logic -
	// - Write Response -
}
router := mux.NewRouter() //link routes to handlers
router.HandleFunc("/alarms", listAlarms).Methods("GET")
router.HandleFunc("/persons/{id}",  updatePerson).Methods("PUT")

middlewareStack := negroni.New() //middleware stack
middlewareStack.use(requestID)   //request ID middleware
middlewareStack.use(authorize)	 //authorization middleware
middlewareStack.use(throttle)    //throttle middleware
middlewareStack.UseHandler(router) //router is the last piece of middleware

http.Handle("/", stack) //listen for http requests

func listAlarms(res http.ResponseWriter, req *http.Request){
	// - Business Logic - 
	// - Write Response -
}

func updatePerson(res http.ResponseWriter, req *http.Request){
	// - Business Logic -
	// - Write Response -
}
//request ID middleware
AddMiddleware(middleware.RequestID())

//logging middleware
AddMiddleware(middleware.LoggingMiddleware(rootLogger))

//rate limiting middleware
var rootLimiter = lrLimiter.NewLimiterMap(10, 200, 2)
AddMiddleware(middleware.RateLimitingMiddleware(rootLimiter))

//get user info in the context for use in middleware/controllers
AddMiddleware(middleware.TokenInfo)

//Authorization checks
AddMiddleware(middleware.Auth(authService, domain.Read), `/cases/{id}`)
AddMiddleware(middleware.Auth(authService, domain.Update), `/cases/{id}`, "PUT")

//stop changes on a closed case
AddMiddleware(middleware.ClosedCheck(), `/cases/{id}`, "PUT", "POST", "DELETE")

Real Example

Pros

  • one touch point
  • isolate concerns
  • potential to stop things from slipping through the cracks

Cons

  • magic / hidden
  • tightly coupled to URIs

deck

By Chris Langager