Search code examples
javascriptfetch

Why does the "append" method in javaScript does not return an array?


Here is an API call, which needs some values to return a specific set of products,

issue

  • "category_slug" has to be an array but for some reason, the API says it's not. what is the problem here?

const url = new URL(
            "https://someApi/products"
        );
        
        let params = {
            "limit": "10",
            "page": "1",
            "category_slug": ["shoes"]
        };

        // "limit" is "how many products in on one page".
        // "page" is the fetched page with the specific "limited" products.

        //issue
        // "category_slug" is a specific products category, this has to be an array but for 
        //  some reason, the API says it's not. what is the problem here?
        
        Object.keys(params)
            .forEach(key => url.searchParams.append(key, params[key]));

        //here I'm appending the specific value in {params} to the URL.


        let headers = {
        "Accept": "application/json",
        "Content-Type": "application/json",
    };
        

        
        fetch(url, {
            method: "GET",
            headers: headers,
        })
            .then(response => response.json())
            .then(json => console.log(json));


Solution

  • See, you expect too little and too much at the same time of such a beautiful thing as URLSearchParams.

    Too little, because usually you can just pass the whole params object into its constructor without wasting time on keys, forEach, etc...

    const url = new URL('https://example.com/');
    const params = {
      limit: 10,
      page: 1
    };
    url.search = new URLSearchParams(params); // yes, that easy
    
    console.log(url.toString()); 
    // https://example.com/?limit=10&page=1
    

    Too much, because URLSearchParams is not designed to work with arrays. When appended element is an array, it's just stringified:

    const url = new URL('https://example.com/');
    const params = {
      slug: [1, 2, 3]
    };
    url.search = new URLSearchParams(params);
    console.log(url); // https://example.com/?slug=1%2C2%2C3
    

    In this case, slug param got 1,2,3 (result of [1, 2, 3].toString()) assigned to it (and all the commas were urlencoded - replaced by %2C sequence).

    Your API might actually work with this, but there's a huge chance it expects array args to be passed in the following format:

    https://example.com/?slug=1&slug=2&slug=3
    

    ... yet even this might not work, if API expects array args to be passed with [] appended to each key, like this:

    https://example.com/?slug[]=1&slug[]=2&slug[]=3
    

    So you'll have to check your API (it's hard to debug such things just by looking into crystal ball, you know...), take its flavor into account - and process your items separately. For example,

    const url = new URL('https://example.com/');
    const params = {
      limit: 10,
      page: 1
    };
    url.search = new URLSearchParams(params);
    
    const slugs = [1, 2, 3];
    url.search += ['', ...slugs.map(
      slug => `category_slug[]=${encodeURIComponent(slug)}`)].join('&');
    
    console.log(url.toString());