Writing HTTP Middleware In Go Shiju Varghese GopherCon India 2016
Agenda • Introduction to HTTP Middleware • Writing HTTP Middleware with Negroni
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) }
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. !
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)) }
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
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	}) }
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
! ! 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
Middleware Chaining http.Handle("/",	middlewareFirst(middlewareSecond(loggingHandler( http.HandlerFunc(index)))))
Using HTTP Middleware with Negroni Package
Install Negroni:! $ go get github.com/codegangsta/negroni! Import Negroni package:! import "github.com/codegangsta/negroni"
//	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) }
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 }
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() }
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), ))
Applying an Authentication Middleware into Specific Routes
//	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) !	} }
//	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 }
THANKS Shiju Varghese! gophermonk@gmail.com https://medium.com/@shijuvar https://github.com/shijuvar

Writing HTTP Middleware In Go