I'm not sure why my route isn't being matched. localhost:8000
matches and I get the expected output but NOT localhost:8000/admin/test
. I am getting 404
when I try to match /admin/test
on the browser.
I wanted to organize my code this way because I wanted to contain the routes and other subroutes within each package
.
project structure
/admin
admin.go
main.go
main.go
package main
import (
"example.com/liondancer/playground/admin"
"fmt"
"github.com/gorilla/mux"
"log"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi there!")
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/", handler)
r.PathPrefix("/admin").Handler(admin.NewHandler())
log.Fatal(http.ListenAndServe(":8000", r))
}
admin.go
package admin
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
)
type Handler struct {
router *mux.Router
}
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.router.ServeHTTP(w, r)
}
func NewHandler() *Handler {
h := &Handler{}
r := mux.NewRouter()
h.router = r
h.addRoutes()
return h
}
func (h *Handler) addRoutes() {
fmt.Print("hi here"). // <--- printed here to prove func gets ran.
h.router.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "test")
})
}
Your nested handler never matches because you are not removing the URL prefix of the earlier handler. A quick fix to show what I mean:
// h.router.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
// quick fix
h.router.HandleFunc("/admin/test", func(w http.ResponseWriter, r *http.Request) {
Obviously you want your nested handler to be unaware how it is nested, so when registering the sub-handler, strip the URL prefix, so your sub-handler will match:
// r.PathPrefix("/admin").Handler(admin.NewHandler())
// better
r.PathPrefix("/admin/").Handler(
http.StripPrefix(
"/admin",
admin.NewHandler(),
),
)