2

Hi I'm having issues sending an array with URLSearchParams. My code is as follows:

const worker = async(endpoint, method, parameters) => {
    let body;
    if (typeof parameters === 'object' && parameters !== null) {
        body = new URLSearchParams()
        for (const key in parameters) {
            body.append(key, parameters[key])
        }
    }

    try {
        const response = await fetch(endpoint, {
            method: method,
            body: body || null
        });

        const json = await response.json();
        if (json.status === 200) {
            return Promise.resolve(json.data)
        }

        return Promise.reject(json.message);
    } catch(error) {
        return Promise.reject('500 Encountered a server error')
    }
};

I iterate the parameters object and create a new URLSearchParams object. One of my parameters is an array I have logged the value of the parameter just before body.append(key, parameters[key]) is executed and it is indeed an array: Array(1) ["user"]. However when I check my express server and read the response the value of the parameter is "user" and not ["user"]. I have confirmed it isn't an issue with my express server because the same request works in Postman. What am I doing wrong here?

Kex
  • 8,023
  • 9
  • 56
  • 129

2 Answers2

4

You can only append strings to a URL.

If you pass an array as the argument to append it will be stringified (with an implicit call to the toString method, which is equivalent to .join(",").

If you want to pass an array of data, then you need to encode it somehow. How you do that depends on how you backend expects the data to be encoded.

The traditional approach is to use duplicate keys:

const myArray = parameters[key];
myArray.forEach(value => body.append(key, value)

The PHP approach, which is supported by the body-parser module with the extended option, is to make sure the key ends in the characters [] so that the data is flagged as being an array even if there is only one item in it.

const myArray = parameters[key];
myArray.forEach(value => body.append(`${key}[]`, value);

You implied that you expect the value to include square brackets, which suggests you are wanting the array to be JSON encoded, in which case you have to do that explicitly:

 body.append(key, JSON.stringify(parameters[key]))
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • I am actually using trying to do url encoding for the requests. I examined my postman and realized the key does indeed need `[]` so added this `if (Array.isArray(parameters[key])) { body.append(key + '[]', parameters[key])}` and now it works. Thanks! – Kex Jun 07 '20 at 14:09
  • @Kex — That's only going to work if there is a *single* value. You need to loop over all the values as per my second example. – Quentin Jun 07 '20 at 14:12
  • Yes that's part of a loop too. – Kex Jun 08 '20 at 02:45
0

As already pointed out by Quentin, everything that gets passed to the append function gets stringified. In case you are looking for a function that automatically appends array values as multiple entries/keys in the query string, here you go:

function convertToQueryUrl(obj: never): string {
    const params = new URLSearchParams(obj);
    for (const [key, value] of Object.entries(obj)) {
        if (Array.isArray(value)) {
            params.delete(key);
            value.forEach((v) => params.append(key, v));
        }
    }
    return params.toString();
}
Tom Böttger
  • 585
  • 7
  • 12