Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi-value query string params #164

Open
silverskater opened this issue Mar 27, 2024 · 8 comments
Open

Multi-value query string params #164

silverskater opened this issue Mar 27, 2024 · 8 comments
Assignees
Labels
dependencies Pull requests that update a dependency file enhancement New feature or request idea improvement

Comments

@silverskater
Copy link

silverskater commented Mar 27, 2024

Multi-value query string params are not supported
ENDPOINT?sections=90&sections=130

Imposter request:

  {
    "request": {
      "method": "GET",
       "endpoint": "/search",
      "params": {
        "sections": "130"
      }
    },

It only finds the first value i.e. 90, but never the second.

Also tried the PHP-way sections[]=90&sections[]=130 - this does nothing at all, the param would probably be sections[].

Suggestion:

      "params": {
        "sections": ["90","130"]
      }

Or maybe some other way to work with the full query string.

@joanlopez joanlopez self-assigned this Mar 28, 2024
@joanlopez joanlopez added enhancement New feature or request idea improvement dependencies Pull requests that update a dependency file labels Mar 28, 2024
@joanlopez
Copy link
Member

Hi @silverskater,

Thanks for your feature request, I definitely think that it would be nice to have support for such cases.
However, after a quick look, I realized that the source of the problem is in gorilla/mux, the library we use for routing.

So, although we could easily add support for reading a JSON as you suggested (e.g. "sections": ["90","130"]), I noticed that calling twice r.Queries(k, v) with the same key and different values doesn't match, which means that this would need to be fixed in gorilla/mux first.

Would you mind opening an issue there? Otherwise, I could do it, even try to open a pull request with the fix, but it would take longer, as I don't have much capacity right now.

Thanks! 🙇🏻

@silverskater
Copy link
Author

Hi @joanlopez I'm not sure it wouldn't work in gorill/mux. At first look it seems possible. The values are not stored in a HashMap, each call simply adds a new check

r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], regexpTypeQuery);

https://github.com/gorilla/mux/blob/976b536446a77de8de2d5559c78f612970fb5e37/route.go#L391

It might even work like

r.Queries("sections", "90", "sections", "130")

But if I got it wrong I'd be happy to create a new issue for it in gorilla/mux.

@joanlopez
Copy link
Member

Hey @silverskater,

Yeah, you can call r.Queries more than once, or just pass multiple key values, as in your example. As you pointed out, it keeps adding regexpTypeQuery matchers (r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], regexpTypeQuery);).

However, the problem is on the "match" side, as it is performed by the following code:

func (r *routeRegexp) matchQueryString(req *http.Request) bool {
	return r.regexp.MatchString(r.getURLQuery(req))
}

https://github.com/gorilla/mux/blob/main/regexp.go#L278-L280

where r.getURLQuery(req) looks like:

// getURLQuery returns a single query parameter from a request URL.
// For a URL with foo=bar&baz=ding, we return only the relevant key
// value pair for the routeRegexp.
func (r *routeRegexp) getURLQuery(req *http.Request) string {
	if r.regexpType != regexpTypeQuery {
		return ""
	}
	templateKey := strings.SplitN(r.template, "=", 2)[0]
	val, ok := findFirstQueryKey(req.URL.RawQuery, templateKey)
	if ok {
		return templateKey + "=" + val
	}
	return ""
}

https://github.com/gorilla/mux/blob/main/regexp.go#L225-L238

And as you can see there, it only looks for the first query key (findFirstQueryKey). Their docs states:

// findFirstQueryKey returns the same result as (*url.URL).Query()[key][0].
// If key was not found, empty string and false is returned.

So, it is impossible to get it working with two different values for the same key. In fact, if you try to build a small example, with your params, you'll notice that, depending on the order of the query parameters, it matches or not even for a single key-value.

For instance, if you only use:

r.Queries("sections", "130")

Then,

  • ENDPOINT?sections=130 works, and it should because the only query key-value matches.
  • ENDPOINT?sections=130&sections=90 works, and it should because the only key-value required matches.
  • ENDPOINT?sections=90&sections=130 doesn't work, and it should because the only key-value required matches, but as it only checks the first it encounters (sections=90 in this case), it determines it doesn't match.

So, unless I'm missing something, or getting something wrong, that logic must be changed in gorilla/mux first. Right?

Thanks! 🙇🏻

@joanlopez
Copy link
Member

joanlopez commented Mar 28, 2024

Or maybe some other way to work with the full query string.

After a short discussion with @aperezg, he made me recall that, unless I'm wrong, it should work by specifying the entire URL as the endpoint field in your imposter. Something like:

{
    "request": {
      "method": "GET",
       "endpoint": "/search?sections=90&sections=130",
      }
}

We know it's far from ideal, because it's very dependant on order, and doesn't work very well with other types of matches, and for instance lacks proper support for regular expressions (so I think we should still push for that fix) in gorilla/mux, but it might be enough for your use case.

I hope it helps! 🤞🏻

@silverskater
Copy link
Author

Thank you @joanlopez , this information helped me to create a well documented feature request: gorilla/mux#754

@Ranveer777
Copy link

Ranveer777 commented May 28, 2024

@joanlopez For your reference gorilla/mux#754 (comment)

@silverskater
Copy link
Author

Thank you @Ranveer777

@joanlopez gorilla/mux seems to support multiple values, even AND instead of OR.

@joanlopez
Copy link
Member

joanlopez commented Jun 13, 2024

Hey @silverskater,

even AND instead of OR.

Could you bring an example of AND? I cannot fully see how to do so from what's suggested there.

Thanks! 🙇🏻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dependencies Pull requests that update a dependency file enhancement New feature or request idea improvement
Projects
None yet
Development

No branches or pull requests

3 participants