Closed vdenisenko-waverley closed 9 months ago
This is how most backends interpret it - an empty array means there's nothing there, so there's nothing lost. Can you elaborate on the use cases?
I'm trying to persist query string which contains complex JSON structure on page refresh. This is why inconsistency matters for my case.
Currently I have to iterate through all JSON fields recursively and append missing fields, to properly initialize JSON on page refresh - which looks not clean and brings unnecessary complication to process.
Is there a reason why the code interacting with your complex structure can't create the structure when needed, rather than requiring it be initialized already?
This is exactly what I have to do, just noticed it is strange that I can't get back same object which was stringified.
JSON itself doesn't provide that guarantee; generally stringify(parse(stringify(x)) === stringify(x)
, but not necessarily parse(stringify(parse(x)))
giving you the same object as parse(x)
.
Did Anybody find workaround for this issue. my use case is, i am trying to render client using parsed data stored in url, i need to preserve all the state during qs.stringify().
This is necessary for cases like the mongo{ query: {$eq: []}}
Seems like sending a query argument that might be empty (like an array of filter fields) is a pretty common use case. I'm fighting with this now.
I could see a case where foo: []
serializes to foo[]
- no equals sign - but i can't see how it would make sense in anything but the "brackets" and "comma" arrayFormat cases, since there's no way to represent an empty array otherwise.
I am having the same issue. Was there a fix to this?
@damonblack @nikkwong @vdenisenko-waverley - if you pass in JSON.stringify([]) this worked for me.
const query = { showItems: JSON.stringify([])}
I'm working on a project where the query parameters are used to specify overrides, falling back to defaults for missing parameters. In this scenario, foo=[]
(where []
represents an empty array) tells the backend to use an empty array for foo
; this is distinct from omitting foo
, which tells the backend to use defaults (and this default is not empty). We've worked around this for now by doing our own processing on a string value (joining/splitting on a delimiter with the empty string representing an empty array), but it would be nice to have this handled by the library.
@jmbtutor would serializing to just foo[]
, without an equals sign, be sufficient to convey that semantic?
If so, I'd be willing to accept a PR for an option to both parse and stringify that explicitly preserved empty arrays and objects in this manner.
I ran into a case where I'm using Joi array conditionals to control the attributes returned by the model. When there's no attributes in the req we use defaults, when the attributes array is empty we don't return any attributes, only associations. Was surprised to find out we couldn't pass empty arrays with qs. Is there a better solution to passing empty arrays in the query?
const query = { where: { id: 101 }, attributes: [], include: ['addresses'], }
This is how most backends interpret it - an empty array means there's nothing there, so there's nothing lost. Can you elaborate on the use cases?
Sometimes the backend parse the query string to know what was requested, for example, an update request needs to know which field needs updating; If a field of array needs to be cleared, the backend might be expecting list: []
, but the result might not be achieved if the library just drop this field.
@wisetwo in which of these scenarios can the backend not be changed to adapt to the frontend (which it should always do, since the frontend should never have to change for the sake of the backend)?
would serializing to just
foo[]
, without an equals sign, be sufficient to convey that semantic?
@ljharb Sorry, I just noticed this ping. As long as that deserializes to an empty array, I think that should be fine. It communicates that the option is specified and that the value is empty.
I've just spent a few hours debugging this exact issue, I send an object containing various properties to my back end, some of which are arrays, in the case that these are empty they are essentially being ignored. I do some processing on the object and then return the modified object back to my front end. With the empty arrays now missing my reactive Vue JS templates on the front end were erroring as I was checking the length of the arrays, which in some instances no longer exist.
I think there are some pretty solid use cases for not ignoring empty arrays. The workaround is having to check if these properties exist and then append empty arrays, ideally I would just be returning all the original object properties.
Turns out that in ASP.net if you define a query parameter from type dictionary and don't pass a value it will automatically be populated by the all query string options. This is a horrible behaviour which they claim is a bug and not a feature :| https://stackoverflow.com/questions/45997570/asp-net-core-fromquery-getting-invalid-parameters-with-dot-sign-inside/46003081#46003081
Nonetheless, it'd be very helpful if qs
define an option to treat empty values (objects, array) the same as null
and output an empty reference. Very very helpful...
I am having the same issue. Was there a fix to this?
@zcrkey nope, if there was a fix the issue would be closed, or linked to an open PR.
At the very least, how about parametrizing the behavior to use an empty string ''
instead of getting rid of the argument altogether? For my use case, I can work with a 0-value like ''
but not with an undefined value.
This is still not ideal. The ideal would be that encoding and decoding could happen back and forth without surprises.
@jose-codaio https://github.com/ljharb/qs/issues/362#issuecomment-750424101 already says i'd accept a PR that added an option.
Surprises are always inevitable, because everybody's expectations are different.
@jose-codaio #362 (comment) already says i'd accept a PR that added an option.
Sorry, missed that.
Surprises are always inevitable, because everybody's expectations are different.
By "surprises", I meant anything preventing the encoding process from being reversible. If an encoding process isn't reversible, then it just adds burden onto the requester. It'd be awesome if I could write the following with no problem.
stringify(parse(stringify(parse(...))))
I understand if we can't always live up to that, but that is the ideal. Otherwise, I'll need custom logic to handle these "surprises".
Out of curiosity: unless x includes non-JSON aspects (eg functions, non-enumerable properties), why would that not work?
What is a "non-JSON aspect"? Try round-tripping a Date object, or a regex, or anything with a .toJSON
method.
It's just not a reasonable expectation that a serialize/deserialize function is reversible for all input - only for a subset of input. It's a great goal, but it's not a reasonable expectation.
What is a "non-JSON aspect"? Try round-tripping a Date object, or a regex, or anything with a .toJSON method.
Dates and regex's are not JSON. JSON is pretty much just:
That method is misleading, but it's probably just to easily dump an object into a JSON-compatible format.
It's just not a reasonable expectation that a serialize/deserialize function is reversible for all input - only for a subset of input. It's a great goal, but it's not a reasonable expectation.
Yeah, that's fair. 😔
{ a: [], b:{ c: [], }, e: '111' } =====> a=&b[c]=&e=111
How to implement such parsing
@zizhuxuaner since you filed #445, i'll hide this comment as off-topic.
I'm having the same problem. I solve my problem by doing a little trick on the frontend. But a parameter would be nice to have empty arrays behave differently.
@HyopeR https://github.com/ljharb/qs/issues/362#issuecomment-750424101 is still waiting for a PR.
Please make a PR, it is very strange functionality
Fixed in #487.
Documentation saying:
However there are cases when this behavior is not desirable. It brings inconsistencies between
stringify
andparse
methods, meaning same object can't be stringified and then parsed. Example:From above example
foo
field is lost.