I want to build a simple api server, and wanted to use gorila mux subrouter
and faced the following issues
//Sample function
func Func1(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello"))
w.WriteHeader(200)
}
func Func2(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("World"))
w.WriteHeader(200)
}
//Issue 1
func TestRouter4(t *testing.T) {
router := mux.NewRouter()
subRouter := router.PathPrefix("/tenant").Subrouter()
subRouter.Methods("GET").HandlerFunc(Func1)
subRouter = subRouter.PathPrefix("/{id:[0-9]+}").Subrouter()
subRouter.Methods("GET").HandlerFunc(Func2)
req := httptest.NewRequest(http.MethodGet, "/tenant", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
blob, _ := ioutil.ReadAll(w.Body)
assert.Equal(t, string(blob), "Hello")
assert.Equal(t, w.Result().StatusCode, http.StatusOK)
req = httptest.NewRequest(http.MethodGet, "/tenant/31231", nil)
w = httptest.NewRecorder()
router.ServeHTTP(w, req)
blob, _ = ioutil.ReadAll(w.Body)
assert.Equal(t, w.Result().StatusCode, http.StatusOK)
assert.Equal(t, string(blob), "World") // Test assertion fails because Func1 is called
}
The above testcase passes if the I change the registration to the following
router := mux.NewRouter()
tenantSubRouter := router.PathPrefix("/tenant").Subrouter()
searchSubRouter := tenantSubRouter.PathPrefix("/{search:[0-9]+}").Subrouter()
searchSubRouter.Methods("GET").HandlerFunc(Func2)
tenantSubRouter.Methods("GET").HandlerFunc(Func1)
//Issue 2
func TestRouter5(t *testing.T) {
router := mux.NewRouter()
tenantSubRouter := router.PathPrefix("/tenant").Subrouter()
searchSubRouter := tenantSubRouter.PathPrefix("/{search:[0-9]+}").Subrouter()
searchSubRouter.Methods("GET").HandlerFunc(Func2)
tenantSubRouter.Methods("GET").HandlerFunc(Func1)
req := httptest.NewRequest(http.MethodGet, "/tenant", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
blob, _ := ioutil.ReadAll(w.Body)
assert.Equal(t, string(blob), "Hello")
assert.Equal(t, w.Result().StatusCode, http.StatusOK)
req = httptest.NewRequest(http.MethodGet, "/tenant/31231", nil)
w = httptest.NewRecorder()
router.ServeHTTP(w, req)
blob, _ = ioutil.ReadAll(w.Body)
assert.Equal(t, string(blob), "World")
assert.Equal(t, w.Result().StatusCode, http.StatusOK)
req = httptest.NewRequest(http.MethodGet, "/tenant/adffasd", nil)
w = httptest.NewRecorder()
router.ServeHTTP(w, req)
blob, _ = ioutil.ReadAll(w.Body)
assert.Equal(t, w.Result().StatusCode, http.StatusNotFound) // Assertion fails as the response is with status code 200 , calls Func1 mapped to route /tenant
}
The above testcase passes with the following code
router := mux.NewRouter()
router.HandleFunc("/tenant", Func1).Methods("GET")
router.HandleFunc("/tenant/{search:[0-9]+}", Func2).Methods("GET")
My inference from this that the PathPrefix().Subrouter()
has some special behavior and use cases. Am I missing some config for PathPrefix().Subrouter()
to work properly or does these have a special use case, if so what is that use case ?