Gorila mux's subroute routing behaviour

94 Views Asked by At

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 ?

0

There are 0 best solutions below