I'm trying to use Gorilla mux router to handle paths that respond to a limited list of strings in the URL. The service I am developing will take files from the caller and pass them through an "adapter" that send them to S3 or OneDrive, depending on the "adapter" specified in the URL. I also require a variable named "schema", which I only mention now because of the weirdness that follows. My test is as follows ({schema} will be set to "test"):
router.HandleFunc("/{adapter:(s3|onedrive)}/{schema:[a-z]+}/check",
func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(fmt.Sprintf(`{"a":"%s","s":"%s"}`,
mux.Vars(r)["adapter"], mux.Vars(r)["schema"])))
}).Methods("GET")
I would expect that going to /s3/test/check would yield {"a":"s3","s":"test"} just as going to /onedrive/test/check should yield {"a":"onedrive","s":"test"} ... however in these cases I am getting {"a":"s3","s":"s3"} and {"a":"onedrive","s":"onedrive"} respectively.
The (s3|onedrive) check seems to be enforced because, for example, trying to go to /dropbox/test/check correctly yields a 404.
Why is the {schema} variable getting the value of the {adapter} variable and how can I fix this?
I think it's because of parenthesis which denote capturing group and yield submatch. It can interfere with gorilla matcher. Just try without parenthesis.
router.HandleFunc("/{adapter:s3|onedrive}/{schema:[a-z]+}/check",
Related
Below is a snapshot of a HTTP Get Call while using Gorilla Mux Router:
usersAPIs.HandleFunc("/users",
middleware.WrapperHandler(th.List)).
Queries("email", "{email}").
Queries("order_by", "{order_by}").
Queries("order_type", "{order_type}").
Queries("page", "{page}").
Queries("limit", "{limit}").
Methods("GET")
Now when GET call happens with all query params e.g.
http://localhost:xxxx/accounts/users?email=a&page=1&limit=4&order_by=a&order_type=b
then the gorilla mux router matches the pattern and takes it to the handler.
But when called like with fewer parameters e.g.
http://localhost:xxxx/accounts/users?email=a&page=1
then it says e.g. 404 not found means Resource path not mapped.
Questions :
#1. What has been missed here, is Go Gorilla Mux Router need all query params?
#2. What to be done If the GET query can come with zero or more parameters? e.g.
http://localhost:xxxx/accounts/users?email=a&page=1
or
http://localhost:xxxx/accounts/users?page=1
Queries(key, value) acts as a path matcher when passed to the route. Since 5 path params are expected, the route would match only if all 5 of them are present.
Though it's a little late to answer this question, but for anyone who stubles upon it later.
I want to have a parameter with slashes in the router in gin.
From what I gathered I can do this by adding a wildcard to the URL. For example: /api/v0/files/*addr
But this approach doesn't work if I want to have the addr in the middle of the URL like /api/v0/*addr/files, and it returns this error:
catch-all routes are only allowed at the end of the path.
I was wondering whether there is another way of having it?
Seems that is a limitation of the Gin framework, as seen # https://github.com/gin-gonic/gin/blob/master/tree.go#L322
You could always invert the order and do a rewrite using a proxy and a regexp (i.e. /api/v0/*addr/files to /api/v0/files/*addr) or only accept methods ending with /files inside your handling function, but I'm afraid that is a hardcoded limitation of the Gin framework.
I want to serve the swagger-ui using gorilla/mux and http.FileServer.
This is the routing that works so far:
router := mux.NewRouter()
router.PathPrefix("/swagger-ui/").Handler(http.StripPrefix("/swagger-ui/",
http.FileServer(http.Dir("swagger-ui/"))))
http.ListenAndServe(":8080", router)
The problem is: only a GET /swagger-ui/ returns the swagger page.
When I do (what most users also expect) a GET /swagger-ui without trailing slash I get a 404.
How can this be solved?
You have probably found the answer as the question is nearly two years old, but I will write the answer here so that anybody who comes across this question can see it.
You just need to define your gorilla router as:
router := mux.NewRouter().StrictSlash(true)
StrictSlash func(value bool) *Router StrictSlash defines the trailing
slash behavior for new routes. The initial value is false.
When true, if the route path is "/path/", accessing "/path" will
perform a redirect to the former and vice versa. In other words, your
application will always see the path as specified in the route.
When false, if the route path is "/path", accessing "/path/" will not
match this route and vice versa.
The re-direct is a HTTP 301 (Moved Permanently). Note that when this
is set for routes with a non-idempotent method (e.g. POST, PUT), the
subsequent re-directed request will be made as a GET by most clients.
Use middleware or client settings to modify this behaviour as needed.
Special case: when a route sets a path prefix using the PathPrefix()
method, strict slash is ignored for that route because the redirect
behavior can't be determined from a prefix alone. However, any
subrouters created from that route inherit the original StrictSlash
setting.
While developing a REST api in Go, how can we use path params? meaning to say what will be the format of the URI?
http://localhost:8765/myapp/{param1}/entries/{param2}
I tried using something like this to create the route but the handler function is not getting invoked.
Please note that, i intent to use only the net/http package , not any other web framework like gorilla mux.
What I tend to do is nested handlers. "/" is handled by the root handler. It pops the first part of the path, assigns the rest back to req.URL.Path (effectively acting like StripPrefix), determines which handler handles routes by that prefix (if any), then chains the appropriate handler. If that handler needs to parse an ID out of the path, it can, by the same mechansim - pop the first part of the path, parse it as necessary, then act.
This not only has no external dependencies, but it is faster than any router could ever be, because the routing is hard-coded rather than dynamic. Unless routing changes at runtime (which would be pretty unusual), there is no need for routing to be handled dynamically.
Well this is why people use frameworks like gin-gonic because this is not easy to do this in the net/http package IIUC.
Otherwise, you would need to strings.Split(r.URL.Path, "/") and work from those elements.
With net/http the following would trigger when calling localhost:8080/myapp/foo/entries/bar
http.HandleFunc("/myapp/", yourHandlerFunction)
Then inside yourHandlerFunction, manually parse r.URL.Path to find foo and bar.
Note that if you don't add a trailing / it won't work. The following would only trigger when calling localhost:8080/myapp:
http.HandleFunc("/myapp", yourHandlerFunction)
Is is possible to use Gorilla's context.ClearHandler() as middleware for Negroni like I've seen it used as middleware for Alice? Something like:
n.Use(context.ClearHandler())
At the moment I'm calling context.Clear(r) after every response but I would prefer the tidying up to be taken care of automatically. I'm currently getting the following error:
cannot use context.ClearHandler() (type http.Handler) as type negroni.Handler in argument to n.Use:
http.Handler does not implement negroni.Handler (wrong type for ServeHTTP method)
have ServeHTTP(http.ResponseWriter, *http.Request)
want ServeHTTP(http.ResponseWriter, *http.Request, http.HandlerFunc)
But I'm not sure what the error message is telling me.
Negroni.Use() expects a parameter of type negroni.Handler but Gorilla's context.ClearHandler() returns a value of type http.Handler.
Good thing is that there is an alternative Negroni.UseHandler() method which expects an http.Handler so just use that. Note that context.ClearHandler() also expects another http.Handler:
otherHandler := ... // Other handler you want to clear
n.UseHandler(context.ClearHandler(otherHandler))
Notes:
The Router from the gorilla/mux package automatically calls context.Clear() at the end of a request lifetime, so if you are using it you don't need to clear the context using context.ClearHandler(). You only need to use it for other / custom handlers (unless you want to call context.Clear() manually).