Gorilla mux route within route

Hello,

How can we have a route within route with gorilla mux?
I have multiple crons under /crons/ and want to have individual functions to handle and process each crons based on file name.

package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
)

func main() {
	route()
}
func hello(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Hello World !!!"))
}
func ProcessCrons(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Crons route"))
	/* How to write multiple routes here */
	//r.PathPrefix("/crons/add_data.php").HandlerFunc(AddDataCron).Methods("GET", "POST")
	//r.PathPrefix("/crons/remove_data.php").HandlerFunc(RemoveDataCron).Methods("GET", "POST")
}
func route() {
	r := mux.NewRouter()
	r.PathPrefix("/hello").HandlerFunc(hello).Methods("GET", "POST")
	r.PathPrefix("/crons/").HandlerFunc(ProcessCrons).Methods("GET", "POST")
	server := &http.Server{
		Addr:         ":8080",
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  5 * time.Second,
		Handler:      handlers.CompressHandler(r),
	}
	err := server.ListenAndServe()
	if err != nil {
		fmt.Println(err)
	}
}

Playground link

How can I do it? Can someone please help.

Edit 1:

As per file structure ProcessCrons() is under another package. For explanation purpose I have included it under main package

Hi @ganesh_salunkhe,

Did you try using a Subrouter?

From the docs:

func (*Route) Subrouter

func (r *Route) Subrouter() *Router

Subrouter creates a subrouter for the route.

It will test the inner routes only if the parent route matched. For example:

r := mux.NewRouter() 
s := r.Host("www.example.com").Subrouter() 
s.HandleFunc("/products/", ProductsHandler) 
s.HandleFunc("/products/{key}", ProductHandler) 
s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)

Here, the routes registered in the subrouter won’t be tested if the host doesn’t match.

Sounds like this could match your use case, except that your scenario would use PathPrefix() instead of Host().

1 Like

Hello @christophberger ,

Yes. But how can I use SubRoute in ProcessCrons() ? As per per file my structure ProcessCrons() this is in another package. And I am trying to have subroute in that package.

For explanation purpose I had to include it under main package.
Sorry I should have mentioned it earlier.

Which Go router should I use? (with flowchart)

https://www.alexedwards.net/blog/which-go-router-should-i-use

Thanks for clarifying. Is there a particular reason for distributing the router across different packages?

Application is having multiple independent modules. And each module will have multiple routes / Sub routes. Keeping all under same package could be difficult to manage a bit. That’s why I am trying to keep them in different different packages.

In this case you could maybe write a function in the router package for registering a HandlerFunc for a particular route. Each package that implements a handler can then register that handler for the desired route.

The routing code would then not need to hard-code all possible handlers for any given route or sub-route. It would only go through the list of registered routes and handlers and add them to the router.

To minimize dependencies between packages, the main package (or some aggregating package) can do the wiring as needed.

I’ve actually done something similar and you’re close. In your main package create a subrouter and pass the subrouter to a function in your other package:

// Our main router
r := mux.NewRouter()
// Crons subrouter
cronsRouter := r.PathPrefix("/crons").Subrouter()
// Pass subrouter to our handler
CronsRouterHandler(cronsRouter)

… and then in your crons (or whatever) package:

// CronsRouterHandler serves content for crons.
func CronsRouterHandler(r *mux.Router) {
	// Note that since this is a subrouter, r.Path("/add_data.php")
	// will map to /crons/add_data.php. It's up to the package that
	// calls this handler func to care about that. You could also listen
	// for these crons routes based on host etc.
	r.Path("/add_data.php").Methods("GET", "POST").HandlerFunc(AddDataCron)
	r.Path("/remove_data.php").Methods("GET", "POST").HandlerFunc(RemoveDataCron)
}

I believe that should get you where you need to go!

1 Like

@christophberger @GonzaSaya @Dean_Davidson
Thank you for answers.

Its exactly what I have been looking for.Thank you.