qs
qs copied to clipboard
Is there an option to prevent value of the same key being populating into an array?
Hi there,
I'm trying to figure out if qs.parse
allow us to update the query key value instead of collecting those as an array from the doc, but I can not find anything about that so I'm asking here.
By default,
qs.parse('?num=1&num=2') === { num: ['1', '2'] };
Instead, I just care about the last value assigned to num
in the query. i.e.
qs.parse('?num=1&num=2', { some_option: true }) === { num: '2' };
Is there a some_option
to do so?
I'm working on an API and want a consistent way to handle the value. It is annoying to check if the query value is an array for a given key every single time (and it can be an object sometimes)... and at this point I decided to ignore all other value but the latest bound to the key.
But I guess people may also want only the first key value is preserved?! (e.g. that is how StarkOverflow handled their duplicated query key.)
Thanks!
One common way it's done is that array keys always have a []
at the end of the name - that's how PHP and Rails do it, for example.
I don't believe there's currently an option to treat duplicate non-array keys as "last one wins" (I don't think "first one wins" would make any sense).
However, since in my experience the most typical webserver setups are:
-
a=1&a=2
gives a as2
(a[]=1&a[]=2
gives a as[1, 2]
) -
a=1&a=2
gives a as[1, 2]
(a[]=1&a[]=2
gives a as[1, 2]
)
it seems like a reasonable option to add to parse
. For stringify, you'd want the arrayFormat: brackets
option (using "repeat" with this new parsing option would lose information).
@ljharb Yeah
I see. I currently just added a function to modify the result from qs.parse()
in my express app for recursivly handling the last-one-win case (so that I don't need to check if it is a string or array every time, and being safely use string method upon the value of a key).
If add this option is considered, then I actually would suggest to also support first-one-win as an option. It was rarely seemed, but some website does it, e.g. StackOverflow.
There should also be an option to do the exact opposite, i.e. always create an array. That would make code easier that expects 1 or more values for an option - currently I need to check if it's an array and otherwise create one from it.
@leoyli I would say this should be the default behavior, and an option to always create an array should be added for those that want that... i'm dealing with a prod bug caused by this unexpected behavior right now...
I think there should be an arrayFormat
for parse the same way it is for stringify, so that you can specify brackets/commas/repeat
As a partial workaround however a repeat
option would work too - set it to true
by default to avoid breaking changes. Setting it to false
will make each same key override the previous one unless it's a bracket.
something like this, instead of
https://github.com/ljharb/qs/blob/e39c235760b58dfaf3a8b5b18b8ff85331e9ddd0/lib/parse.js#L90-L94
we can do
if (has.call(obj, key) && (bracketEqualsPos !== -1 || options.repeat)) {
obj[key] = utils.combine(obj[key], val);
} else {
obj[key] = val;
}
that way
qs.parse('a=1&a=2') === { a: [1, 2] } // same as it is right now
qs.parse('a=1&a=2', { repeat: false }) === { a: 2 }
WDYT?
@dreyks it makes sense to me to try to make the APIs of parse and stringify more consistent; if you think you could draft a PR with tests that does that for arrayFormat, i'd be happy to review it.
gonna give it a try when time allows
#329
How is this feature going?🧐
How is this feature going?🧐
How is this feature going?🧐