I've been working on a Go project where gorilla/mux is used as the router.
I need to be able to have query values associated with a route, but these values should be optional.
That means that I'd like to catch both /articles/123
and /articles/123?key=456
in the same handler.
To accomplish so I tried using the r.Queries
method that accepts key/value pairs:
router.
Path("/articles/{id:[0-9]+}").Queries("key", "{[0-9]*?}")
but this makes only the value (456
) optional, but not the key
.
So both /articles/123?key=456
and /articles/123?key=
are valid, but not /articles/123
.
Edit: another requirement is that, after registering the route, I'd like to build them programatically, and I can't seem to work out how to use r.Queries
even though the docs specifically state that it's possible (https://github.com/gorilla/mux#registered-urls).
@jmaloney answer works, but doesn't allow to build URLs from names.
I would just register your handler twice.
router.Path("/articles/{id:[0-9]+}").
Queries("key", "{[0-9]*?}").
HandlerFunc(YourHandler).
Name("YourHandler")
router.Path("/articles/{id:[0-9]+}").HandlerFunc(YourHandler)
Here is a working program to demonstrate. Notice that I am using r.FormValue
to get the query parameter.
Note: make sure you have an up to date version go get -u github.com/gorilla/mux
since a bug of query params not getting added the built URLs was fixed recently.
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/mux"
)
var router = mux.NewRouter()
func main() {
router.Path("/articles/{id:[0-9]+}").Queries("key", "{key}").HandlerFunc(YourHandler).Name("YourHandler")
router.Path("/articles/{id:[0-9]+}").HandlerFunc(YourHandler)
if err := http.ListenAndServe(":9000", router); err != nil {
log.Fatal(err)
}
}
func YourHandler(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
key := r.FormValue("key")
u, err := router.Get("YourHandler").URL("id", id, "key", key)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
// Output:
// /articles/10?key=[key]
w.Write([]byte(u.String()))
}
If you register query parameters they are required doc:
All variables defined in the route are required, and their values must conform to the corresponding patterns.
Because those parameters are optional you just need to check for them inside of a handler function: id, found := mux.Vars(r)["id"]
. Where found
will show if the parameter in the query or not.
Seems like the best way to handle optional URL parameters is to define your router as normal without them, then parse the optional params out like this:
urlParams := request.URL.Query()
This returns a map that contains the URL parameters as Key/Value pairs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With