Skip to content

Stringify with "arrayFormat: comma" encodes objects inside arrays as "[object Object]" #378

@FreekyMage

Description

@FreekyMage

Tested on version 6.9.4

Stringify with arrayFormat: comma encodes objects inside arrays as [object Object]

I took this code from the examples:

qs.stringify({ a: { b: { c: 'd', e: 'f' } } });
// 'a[b][c]=d&a[b][e]=f'

and added an array around the inside object

qs.stringify({ a: { b: [{ c: 'd', e: 'f' }] } }, { encode: false, arrayFormat: 'comma' })
// 'a[b]=[object Object]'

The inside data is lost this way.

I tried the allowDots setting too, but that didn't fix anything.

I'm not sure what the output should be like exactly, but this is unusable right now.
In my project I did Array.map(p => ${p.ID}::${p.Value}), but that's very specific and I'm unsure if the :: is a good seperator.

Activity

ljharb

ljharb commented on Jan 13, 2021

@ljharb
Owner

I agree the current behavior is unusable. However, it is really unclear to me what the format should be, because the "comma" format doesn't work the same way normal query strings work. In other words, i have no idea whatsoever how an object inside an array would be represented in that format. Any suggestions?

cc @daggerjames @bryanlarsen who originally implemented/requested this format

added a commit that references this issue on Jan 13, 2021
ls-urs-keller

ls-urs-keller commented on Sep 22, 2022

@ls-urs-keller

I guess arrayFormat: 'comma' should only be applied to an array with primitives e.g. number, string ...

ljharb

ljharb commented on Sep 22, 2022

@ljharb
Owner

@ls-urs-keller one possibility is that qs could throw if it encounters a non-primitive when stringifying arrayFormat comma, but maybe there's something useful to be done instead.

ls-urs-keller

ls-urs-keller commented on Sep 22, 2022

@ls-urs-keller

My need is compact query strings when possible, but still, have it work correctly for nested object arrays. I'm using this workaround for the moment:

const stringifyOpts = {
  allowDots: true,
  filter: (_prefix: string, value?: unknown): unknown => {
    const isNonNullPrimitive = (x?: unknown): boolean => !!x && Object(x) !== x;
    return Array.isArray(value) &&
      value.filter((v) => !isNonNullPrimitive(v) || v.indexOf(',') > -1).length === 0
      ? value.join(',')
      : value;
  },
};
stringify(queryParams, stringifyOpts)
ljharb

ljharb commented on Sep 22, 2022

@ljharb
Owner

You're missing a few primitive types; i'd suggest doing Object(x) === x to determine if something's an object or not.

ls-urs-keller

ls-urs-keller commented on Sep 22, 2022

@ls-urs-keller

You're missing a few primitive types; i'd suggest doing Object(x) === x to determine if something's an object or not.

Thank you. How about now?
Just wondering if this remark is valid here as well https://github.com/ljharb/qs/blob/main/lib/stringify.js#L51 ?

nandi95

nandi95 commented on Sep 22, 2022

@nandi95

@ls-urs-keller one possibility is that qs could throw if it encounters a non-primitive when stringifying arrayFormat comma, but maybe there's something useful to be done instead.

This is a good idea as people will likely get tripped up by this

ls-urs-keller

ls-urs-keller commented on Sep 22, 2022

@ls-urs-keller

@ls-urs-keller one possibility is that qs could throw if it encounters a non-primitive when stringifying arrayFormat comma, but maybe there's something useful to be done instead.

This is a good idea as people will likely get tripped up by this

I would prefer a mixed mode as per my comments above.

ljharb

ljharb commented on Sep 16, 2023

@ljharb
Owner

Howdy, folks that care about the comma array format!

My intuition is that what you want most is either to be able to round-trip things between parse and stringify (which requires [] brackets to be added on one-item arrays in stringify, or on all of them); or, to match the API of a specific server implementation.

If the latter, can folks please describe exactly what they're using and what format it requires? If it supports what qs calls brackets, indices, or repeat, please also explain why you need to use comma over those.

runspired

runspired commented on Sep 23, 2023

@runspired

Most likely every user of JSON:API

https://jsonapi.org/format/#fetching-includes

The value of the include parameter MUST be a comma-separated (U+002C COMMA, “,”) list of relationship paths. A relationship path is a dot-separated (U+002E FULL-STOP, “.”) list of relationship names. An empty value indicates that no related resources should be returned.

21 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @ljharb@runspired@FreekyMage@jelhan@ls-urs-keller

        Issue actions

          Stringify with "arrayFormat: comma" encodes objects inside arrays as "[object Object]" · Issue #378 · ljharb/qs