Also allowing lists to be represented with [] or implicitly
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: https://github.com/seanmonstar/warp/issues/733
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: https://github.com/samscott89/serde_qs/issues/16#issuecomment-450464628
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.
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.
https://github.com/samscott89/serde_qs/blob/69b6269893c003911f86563d1e59750b735c2685/src/de/parse.rs#L29 https://github.com/samscott89/serde_qs/blob/69b6269893c003911f86563d1e59750b735c2685/src/de/parse.rs#L54
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.
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?
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
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.
@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.
@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.
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
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.