62

I am making a request like this:

fetch("https://api.parse.com/1/users", {
  method: "GET",
  headers: headers,   
  body: body
})

How do I pass query string parameters? Do I simply add them to the URL? I couldn't find an example in the docs.

Sarun UK
  • 6,210
  • 7
  • 23
  • 48
Guy
  • 12,488
  • 16
  • 79
  • 119
  • 1
    Possible duplicate of [Setting query string using Fetch GET request](https://stackoverflow.com/questions/35038857/setting-query-string-using-fetch-get-request) – Hirurg103 Jun 30 '18 at 14:29

7 Answers7

74

Your first thought was right: just add them to the URL.

Remember you can use template strings (backticks) to simplify putting variables into the query.

const data = {foo:1, bar:2};

fetch(`https://api.parse.com/1/users?foo=${encodeURIComponent(data.foo)}&bar=${encodeURIComponent(data.bar)}`, {
  method: "GET",
  headers: headers,   
})
Ben Clayton
  • 80,996
  • 26
  • 120
  • 129
41

Short answer

Just substitute values into the URL like this:

const encodedValue = encodeURIComponent(someVariable);
fetch(`https://example.com/foo?bar=${encodedValue}`);

Longer answer

Yes, you just need to add the query string to the URL yourself. You should take care to escape your query string parameters, though - don't just construct a URL like

`https://example.com/foo?bar=${someVariable}`

unless you're confident that someVariable definitely doesn't contain any &, =, or other special characters.

If you were using fetch outside of React Native, you'd have the option of encoding query string parameters using URLSearchParams. However, React Native does not support URLSearchParams. Instead, use encodeURIComponent.

For example:

const encodedValue = encodeURIComponent(someVariable);
fetch(`https://example.com/foo?bar=${encodedValue}`);

If you want to serialise an object of keys and values into a query string, you could make a utility function to do that:

function objToQueryString(obj) {
  const keyValuePairs = [];
  for (const key in obj) {
    keyValuePairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]));
  }
  return keyValuePairs.join('&');
}

... and use it like this:

const queryString = objToQueryString({
    key1: 'somevalue',
    key2: someVariable,
});
fetch(`https://example.com/foo?${queryString}`);
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
5

Here's an es6 approach

const getQueryString = (queries) => {
    return Object.keys(queries).reduce((result, key) => {
        return [...result, `${encodeURIComponent(key)}=${encodeURIComponent(queries[key])}`]
    }, []).join('&');
};

Here we're taking in a queries object in the shape of key: param We iterate and reduce through the keys of this object, building an array of encoded query strings. Lastly we do a join and return this attachable query string.

flashpaper
  • 51
  • 1
  • 2
  • Although we both know that the code is quite straight forward, still add some explanation is preferred for an answer. – keikai Mar 19 '20 at 02:14
  • example: const data = {city:'Amman', country:'Jordan', month: 7, annual: false}; fetch(`http://api.aladhan.com/v1/calendarByCity?${getQueryString(data)}`, { method: "GET" }) – simo Jul 07 '21 at 04:08
4

I did a small riff on Mark Amery's answer that will pass Airbnb's eslint definitions since many teams seem to have that requirement these days.

function objToQueryString(obj) {
  const keyValuePairs = [];
  for (let i = 0; i < Object.keys(obj).length; i += 1) {
    keyValuePairs.push(`${encodeURIComponent(Object.keys(obj)[i])}=${encodeURIComponent(Object.values(obj)[i])}`);
  }
  return keyValuePairs.join('&');
}
ZardozSpeaks
  • 151
  • 2
  • 7
2

My simple function to handle this:

/**
 * Get query string
 *
 * @param   {*}   query   query object (any object that Object.entries() can handle)
 * @returns {string}      query string
 */
function querystring(query = {}) {
  // get array of key value pairs ([[k1, v1], [k2, v2]])
  const qs = Object.entries(query)
    // filter pairs with undefined value
    .filter(pair => pair[1] !== undefined)
    // encode keys and values, remove the value if it is null, but leave the key
    .map(pair => pair.filter(i => i !== null).map(encodeURIComponent).join('='))
    .join('&');

  return qs && '?' + qs;
}

querystring({one: '#@$code', two: undefined, three: null, four: 100, 'fi##@ve': 'text'});
// "?one=%23%40%24code&three&four=100&fi%23%23%40ve=text"
querystring({});
// ""
querystring('one')
// "?0=o&1=n&2=e"
querystring(['one', 2, null, undefined]);
// "?0=one&1=2&2" (edited)
Ievgen S
  • 33
  • 5
1

Yes you should, there are a few classes in JS, that can help you a handy one is https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams

e.g. if you had the params in a javascript object say

let params = {one: 'one', two: 'two'}

you could say this function

let queryString = new URLSearchParams()
for(let key in params){
  if(!params.hasOwnkey())continue
  queryString.append(key, params[key])
}

then you can get your nicely formatted query string by saying

queryString.toString()
kamikazeOvrld
  • 914
  • 8
  • 9
  • 3
    -1; `URLSearchParams` doesn't exist in React Native. The only way to use it is via a polyfill, and this answer doesn't mention that. – Mark Amery Dec 24 '17 at 16:57
  • I think this polyfill is included by default with React Native via [whatwg-fetch](https://www.npmjs.com/package/whatwg-fetch) so `URLSearchParams` should be safe to use, at least as of React Native 0.59. – Eliot Jun 05 '20 at 00:32
0

The accepted answer works, but if you have more params than one it doesn't generalize. I suggest the following approach, which also handles array parameters:

let route = 'http://test.url.com/offices/search';
if (method == 'GET' && params) {
  const query = Object.keys(params)
    .map((k) => {
      if (Array.isArray(params[k])) {
        return params[k]
          .map((val) => `${encodeURIComponent(k)}[]=${encodeURIComponent(val)}`)
          .join('&');
      }

      return `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`;
    })
    .join('&');

  route += `?${query}`;
}
ggorlen
  • 44,755
  • 7
  • 76
  • 106
iuliu.net
  • 6,666
  • 6
  • 46
  • 69