Middlewares as layers

The example implements two layers; authentication and the bottom endpoints. Each layer only needs changing for one reason. This results in simpler testing. Downside; routing is done for each layer.


func AuthLayer(next http.Handler) *http.ServeMux {
	// add public patterns
	mx := http.NewServeMux()
	mx.Handle("GET /fruits", next)

	// anything else is private and requires authentication
	mx.Handle("GET /", protect(next))
	return mx
}

func protect(next http.Handler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// ... implement authorization here ...
		w.WriteHeader(http.StatusUnauthorized)
	}
}

func Endpoints() *http.ServeMux {
	mx := http.NewServeMux()
	mx.Handle("GET /fruits", fruits())
	mx.Handle("GET /keys", keys())
	return mx
}

func TestAuthLayer(t *testing.T) {
	// the layerd design allows for easy replacement of lower layers
	layer := AuthLayer(alwaysOK())
	cases := map[string]int{
		"GET /fruits": 200,		
		"GET /keys":   401,
	}
	checkResp(t, layer, cases)
}

func TestEndpoints(t *testing.T) {
	layer := Endpoints()
	cases := map[string]int{
		"GET /fruits": 200,
		"GET /keys":   200,
		"POST /keys":  405,
	}
	checkResp(t, layer, cases)
}
Files: layerd.go, layerd_test.go