infuse icon indicating copy to clipboard operation
infuse copied to clipboard

Golang middleware - fully compatible with net/http - provides shared contexts

trafficstars

Infuse

Build Status GoDoc

Infuse provides an immutable, concurrency-safe middleware handler that conforms to http.Handler. An infuse.Handler is fully compatible with the Go standard library, supports flexible chaining, and provides a shared context between middleware handlers without relying on global state, locks, or shared closures.

BasicAuth example:


func Example() {
	authHandler := infuse.New().HandleFunc(basicAuth)
	router := http.NewServeMux()
	router.Handle("/hello", authHandler.HandleFunc(userGreeting))
	router.Handle("/goodbye", authHandler.HandleFunc(userFarewell))
	server := httptest.NewServer(router)
	defer server.Close()

	doRequest(server.URL+"/hello", "bob", "1234")
	doRequest(server.URL+"/goodbye", "alice", "5678")
	doRequest(server.URL+"/goodbye", "intruder", "guess")

	// Output:
	// Hello bob!
	// Goodbye alice!
	// Permission Denied
}

func userGreeting(response http.ResponseWriter, request *http.Request) {
	username := infuse.Get(response).(string)
	fmt.Fprintf(response, "Hello %s!", username)
}

func userFarewell(response http.ResponseWriter, request *http.Request) {
	username := infuse.Get(response).(string)
	fmt.Fprintf(response, "Goodbye %s!", username)
}

func basicAuth(response http.ResponseWriter, request *http.Request) {
	username, password, ok := request.BasicAuth()
	if !ok || !userValid(username, password) {
		response.WriteHeader(http.StatusUnauthorized)
		fmt.Fprint(response, "Permission Denied")
		return
	}

	if ok := infuse.Set(response, username); !ok {
		response.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(response, "Server Error")
	}

	if ok := infuse.Next(response, request); !ok {
		response.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(response, "Server Error")
	}
}

The mock package makes it easy to unit test code that depends on an infuse.Handler.