Skip to content

blang/xhandler

 
 

Repository files navigation

XHandler

godoc license Build Status Coverage

XHandler is a bridge between net/context and http.Handler.

It lets you enforce net/context in your handlers without sacrificing compatibility with existing http.Handlers nor imposing a specific router.

Thanks to net/context deadline management, xhandler is able to enforce a per request deadline and will cancel the context when the client closes the connection unexpectedly.

You may create your own net/context aware handler pretty much the same way as you would do with http.Handler.

Read more about xhandler on Dailymotion engineering blog.

Installing

go get -u github.com/rs/xhandler

Usage

package main

import (
	"log"
	"net/http"
	"time"

	"github.com/rs/cors"
	"github.com/rs/xhandler"
	"golang.org/x/net/context"
)

type myMiddleware struct {
	next xhandler.HandlerC
}

func (h myMiddleware) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	ctx = context.WithValue(ctx, "test", "World")
	h.next.ServeHTTPC(ctx, w, r)
}

func main() {
	c := xhandler.Chain{}

	// Add close notifier handler so context is cancelled when the client closes
	// the connection
	c.UseC(xhandler.CloseHandler)

	// Add timeout handler
	c.UseC(xhandler.TimeoutHandler(2 * time.Second))

	// Middleware putting something in the context
	c.UseC(func(next xhandler.HandlerC) xhandler.HandlerC {
		return myMiddleware{next: next}
	})

	// Mix it with a non-context-aware middleware handler
	c.Use(cors.Default().Handler)

	// Final handler (using handlerFuncC), reading from the context
	xh := xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
		value := ctx.Value("test").(string)
		w.Write([]byte("Hello " + value))
	})

	// Bridge context aware handlers with http.Handler using xhandler.Handle()
	http.Handle("/test", c.Handler(xh))

	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal(err)
	}
}

Using existing muxers

How to use it with a non- net/context aware router. Lets try with the Go's ServerMux:

func main() {
	c := xhandler.Chain{}

	// Append a context-aware middleware handler
	c.UseC(xhandler.CloseHandler)

	// Mix it with a non-context-aware middleware handler
	c.Use(cors.Default().Handler)

	// Another context-aware middleware handler
	c.UseC(xhandler.TimeoutHandler(2 * time.Second))

	mux := http.NewServeMux()

	// Use c.Handler to terminate the chain with your final handler
	mux.Handle("/", c.Handler(xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, req *http.Request) {
		fmt.Fprintf(w, "Welcome to the home page!")
	})))

	// You can reuse the same chain for other handlers
	mux.Handle("/api", c.Handler(apiHandler))
}

Context Aware Middleware

Here is a list of net/context aware middleware handlers implementing xhandler.HandlerC interface.

Feel free to put up a PR linking your middleware if you have built one:

Middleware Author Description
xlog Olivier Poitrey HTTP handler logger
xstats Olivier Poitrey A generic client for service instrumentation
xaccess Olivier Poitrey HTTP handler access logger with xlog and xstats
cors Olivier Poitrey Cross Origin Resource Sharing (CORS) support

Licenses

All source code is licensed under the MIT License.

About

XHandler is a bridge between net/context and http.Handler

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Go 100.0%