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

Also allowing lists to be represented with [] or implicitly #35

Open
Gelox opened this issue Nov 1, 2020 · 9 comments
Open

Also allowing lists to be represented with [] or implicitly #35

Gelox opened this issue Nov 1, 2020 · 9 comments

Comments

@Gelox
Copy link

Gelox commented Nov 1, 2020

It seems like there is no clear standardized way of representing lists in a query-string passed in with an HTTP GET operator.
However there seems to be an unofficial way that one should pass the same key with multiple values or a key with [] after it to indicate that it should be interpreted as a list. Here are the sources that I am getting this idea from stackoverflow and wikipedia.

As far as I can tell serde_qs currently only supports specifying a list by indexing it like:
/get_method?somelist[0]=a&somelist[1]=b

would it be interesting to also allow both an explicit list indication without an index like this:
/get_method?somelist[]=a&somelist[]=b
and an implicit list indication by assigning multiple values to the same field like this:
/get_method?somelist=a&somelist=b

What are your thoughts? Some previous discussion can be found here: seanmonstar/warp#733

@samscott89
Copy link
Owner

Hey @Gelox.

Thanks for opening the issue + linking the relevant issue.

I've mostly been trying to follow whatever kind of precedent Rails set with its query parser.
This was my previous position on this: #16 (comment)

I just had a try. It seems like it would be a fairly easy change, to allow repeating keys to deserialize as a sequence... But it wouldn't work for vectors of structs, and it doesn't seem like it would be feasible to make it compatible in the serialization direction. Given that, I would rather keep the current behaviour matching Rails.

@Moggers
Copy link

Moggers commented Dec 22, 2020

I've run into this sort of issue, where I'm trying to use hidden input fields to explicitly send &name=0 in the event the checkbox is unselected (so I can differentiate "I just navigated give me the default" from "I submitted the form and I didn't check the checkbox"), however I have the option of either sending &name=0&name=1 by adding a hidden element and give both inputs the attribute name="name" or I can end up with the qs &name[0]=1 if I give them both the attribute name="name[0]", so it would be nice if the field could be coerced into a scalar if the destination struct has a scalar instead of a collection, as of right now the prior carks it completely, and the latter carks it (I believe) because it expects to deserialize into a vec.

let _ = o.insert(Level::Invalid("Multiple values for one key"));

let _ = o.insert(Level::Invalid("Multiple values for one key"));

I ended up using a deserialize_with in conjunction with an itty bitty fork to just do a replace when it sees duplicate keys instead of kicking the bucket.

@samscott89
Copy link
Owner

Hey @Moggers.

I'm not sure I fully follow. But maybe you could try either making the key "name[]" which would allow multiple elements? And then only use or deserialize the last element?

@Moggers
Copy link

Moggers commented Dec 23, 2020

Hey! Sorry, yeah it seems a bit incoherent because it started off with a call for help but I managed to figure it out a solution for myself.
You're actually right in that sending the values as name[]=0&name[]=1, then just deserializing the last entry would work and wouldn't require me to hack out the "duplicate field" validation, which I do when I send name[0]=0&name[0]=1

@samscott89
Copy link
Owner

Okay that's great! I would still be a little worried that those fields could be re-ordered, and the "last entry" isn't a very robust thing to rely on.

@Gelox
Copy link
Author

Gelox commented Jan 6, 2021

@samscott89 Hi, this has been a dead issue for a while and I haven't thought about it for a while, but bumps bring me back and I've reread it. This is what I've understood from the thread: it would be great to be able to support the unofficial way of passing lists via several parameters that lack an index. Either by repeating the same key with different values of adding a [] after the key. It would also probably not be very difficult to write the code that does this.
However the big hurdle is that serializing this to a Vector is a bit deceptive because it implies the key-value pairs are ordered when we probably don't want to imply that from the url data.

My suggestion is therefore that you allow deserialization of data like this to unordered collections such as HashSet. You could support more unordered collections if you want to but I think HashSet is likely enough since 1 is so much bigger than 0.
I do not know how difficult it would be to ONLY support deserialization to HashSet and not to Vec codewise, perhaps you want it always to be returnable in an Iterator format in which case this might not be the best idea. Up to you, that's what I suggest.

@samscott89
Copy link
Owner

samscott89 commented Jan 6, 2021

@Gelox

adding a [] after the key

I think I missed this in your original question, but you can already do key[]=1&key[]=2 to get repeated values:

https://github.com/samscott89/serde_qs/blob/main/examples/introduction.rs#L118-L127

What isn't currently supported is omitting the [] and treating repeated keys as a vector.

@samscott89
Copy link
Owner

The usage of HashSet instead of Vec is an interesting suggestion though. It would be a lot more explicit, and would be a pretty easy change to make. I don't think it could work for struct values though. E.g. a[b]=1&a[b]=2. Should the a keys be treated as repeating with values {b: 1} and {b: 2}, or are the b keys repeating as a subfield of a. I think the implementation needs to be able to distinguish these

@Gelox
Copy link
Author

Gelox commented Jan 6, 2021

Thank you, I didn't realize that a[]=1&a[]=2 was valid. Or perhaps I knew but I've forgotten.
As for the interpretation of a[b]=1&a[b]=2, you are right. I can't think of a way to distinguish the two scenarios.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants