Does gorilla mux subrouters inherit the middlewares of their parent router?

493 Views Asked by At

The whole question is in the title.

I was searching on SO if a subrouter will use a middleware of its parent, in the case the middleware is applied to the parent router with the method Use(), but I couldn't find a clear concise answer.

I couldn't find that information in the package documentation either, so I decided to test it and post a question and an answer here for everyone in the same case.

In the following code sample, does requesting on /john will trigger the logMiddleware ?

mainRouter := mux.NewRouter()
mainRouter.Use(logMiddleware)
subRouter := mainRouter.PathPrefix("/users/").Subrouter()
subRouter.Handle("/john", johnHandler())
1

There are 1 best solutions below

0
Damien On

Yes, mux subrouters inherit their parent's middlewares when applied with Use() method.

Here is the test I created in case you want to try in your favorite IDE :

router code

package so

import (
    "context"
    "net/http"

    "github.com/gorilla/mux"
)

func newRouter(useMainMiddleware bool) mux.Router {
    mainRouter := mux.NewRouter()
    if useMainMiddleware {
        mainRouter.Use(middleware)
    }
    subRouter := mainRouter.PathPrefix("/users/").Subrouter()
    subRouter.Handle("/test", testHandler())
    return *mainRouter
}

func middleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        r = r.WithContext(context.WithValue(r.Context(), "is_using_middleware", true))
        next.ServeHTTP(w, r)
    })
}

func testHandler() http.Handler {
    return http.HandlerFunc(
        func(w http.ResponseWriter, r *http.Request) {
            if using, castOk := r.Context().Value("is_using_middleware").(bool); castOk && using {
                w.WriteHeader(http.StatusOK)
                return
            }
            w.WriteHeader(http.StatusInternalServerError)
            return
        },
    )
}

test file

package so

import (
    "net/http"
    "net/http/httptest"
    "testing"

    "github.com/stretchr/testify/assert"
)

func TestSubrouterWithMiddleware(t *testing.T) {
    // GIVEN
    request := httptest.NewRequest(http.MethodGet, "/users/test", nil)
    recorder := httptest.NewRecorder()
    router := newRouter(true) // using a middleware
    // WHEN
    router.ServeHTTP(recorder, request)
    // THEN
    assert.Equal(t, http.StatusOK, recorder.Result().StatusCode)
}

func TestSubrouterWithoutMiddleware(t *testing.T) {
    // GIVEN
    request := httptest.NewRequest(http.MethodGet, "/users/test", nil)
    recorder := httptest.NewRecorder()
    router := newRouter(false) // not using a middleware
    // WHEN
    router.ServeHTTP(recorder, request)
    // THEN
    assert.Equal(t, http.StatusInternalServerError, recorder.Result().StatusCode)
}