444

I'm trying to use the new Fetch API:

I am making a GET request like this:

var request = new Request({
  url: 'http://myapi.com/orders',
  method: 'GET'
});
fetch(request);

However, I'm unsure how to add a query string to the GET request. Ideally, I want to be able to make a GET request to a URL like:

'http://myapi.com/orders?order_id=1'

In jQuery I could do this by passing {order_id: 1} as the data parameter of $.ajax(). Is there an equivalent way to do that with the new Fetch API?

Arsen Khachaturyan
  • 7,904
  • 4
  • 42
  • 42
mylescc
  • 5,720
  • 3
  • 17
  • 23

14 Answers14

647

A concise, modern approach:

fetch('https://example.com?' + new URLSearchParams({
    foo: 'value',
    bar: 2,
}))

How it works: When a string (e.g. the URL) is being concatenated with an instance of URLSearchParams, its toString() method will automatically be called to convert the instance into a string representation, which happens to be a properly encoded query string. If the automatic invoking of toString() is too magical for your liking, you may prefer to explicitly call it like so: fetch('https://...' + new URLSearchParams(...).toString())

A complete example of a fetch request with query parameters:

// Real example you can copy-paste and play with.
// jsonplaceholder.typicode.com provides a dummy rest-api
// for this sort of purpose.
async function doAsyncTask() {
  const url = (
    'https://jsonplaceholder.typicode.com/comments?' +
    new URLSearchParams({ postId: 1 }).toString()
  );

  const result = await fetch(url)
    .then(response => response.json());

  console.log('Fetched from: ' + url);
  console.log(result);
}

doAsyncTask();

If you are using/supporting...

  • IE: Internet Explorer does not provide native support for URLSearchParams or fetch, but there are polyfills available.

  • Node: As of Node 18 there is native support for the fetch API (in version 17.5 it was behind the --experimental-fetch flag). In older versions, you can add the fetch API through a package like node-fetch. URLSearchParams comes with Node, and can be found as a global object since version 10. In older version you can find it at require('url').URLSearchParams.

  • Node + TypeScript: If you're using Node and TypeScript together you'll find that, due to some technical limitations, TypeScript does not offer type definitions for the global URLSearchParams. The simplest workaround is to just import it from the url module. See here for more info.

Scotty Jamison
  • 10,498
  • 2
  • 24
  • 30
  • 12
    Thanks for sharing. I think this should be accepted answer. The asked to pass parameters to the fetch API, and although that isn't possible, this answer is pretty bloody close to what that would look like in structure. – Jesse Reza Khorasanee Aug 20 '20 at 22:30
  • 1
    This doesn't appear to correctly handle multiple values for the same key. I was expecting to be able to write `new URLSearchParams({foo: ['bar', 'baz']})` but rather than `foo=bar&foo=baz` it gets escaped as `foo=bar%Cbaz` – jymbob Nov 11 '20 at 15:34
  • 2
    @jymbob to have multiple values, you'll have to use the .append() method on URLSearchParams. e.g. `s = new URLSearchParams({foo: 'bar'}); s.append('foo', 'baz'); s.toString()`. Alternativly, the constructor can take a list of lists instead of an object. `new URLSearchParams([['foo', 'bar'], ['foo', 'baz']]).toString()` See the docs page for more usage info: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams – Scotty Jamison Nov 11 '20 at 15:39
  • @ScottyJamison thanks for responding. I had discovered that from the docs, but it sort of renders URLSearchParams useless for me if I can't pass in a dict and get the expected search param out at the other end. – jymbob Nov 11 '20 at 15:47
  • 5
    An even more concise approach would be to use string interpolation: ``` `https://example.com?${new URLSearchParams({foo: 'value'})}` ``` https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals – RavenHursT Apr 01 '21 at 22:23
  • For anyone wondering why URLSearchParams does not work with arrays, it's because there's no standard way to represent array data as search params, and you'll find competing ways to do this task. See https://stackoverflow.com/questions/6243051/how-to-pass-an-array-within-a-query-string – Scotty Jamison May 12 '21 at 15:23
  • Works like a charm with key, value – AnnABlue Nov 06 '21 at 09:28
  • Node supports fetch now! – ggorlen Mar 15 '22 at 03:40
  • 6
    Be aware that when using typescript you have to use strings as values only. So `bar: 2` should be `bar: '2'`. – Matthew Darton Aug 22 '22 at 16:17
342

Update March 2017:

URL.searchParams support has officially landed in Chrome 51, but other browsers still require a polyfill.


The official way to work with query parameters is just to add them onto the URL. From the spec, this is an example:

var url = new URL("https://geo.example.org/api"),
    params = {lat:35.696233, long:139.570431}
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]))
fetch(url).then(/* … */)

However, I'm not sure Chrome supports the searchParams property of a URL (at the time of writing) so you might want to either use a third party library or roll-your-own solution.

Update April 2018:

With the use of URLSearchParams constructor you could assign a 2D array or a object and just assign that to the url.search instead of looping over all keys and append them

var url = new URL('https://sl.se')

var params = {lat:35.696233, long:139.570431} // or:
var params = [['lat', '35.696233'], ['long', '139.570431']]

url.search = new URLSearchParams(params).toString();

fetch(url)

Sidenote: URLSearchParams is also available in NodeJS

const { URL, URLSearchParams } = require('url');
CodingIntrigue
  • 75,930
  • 30
  • 170
  • 176
  • 1
    There's also https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/toString, tho as of this writing it's still making its way through spec, and not well-supported yet. And the API is more like Java than JS. :/ – ericsoco Sep 14 '16 at 17:57
  • 1
    See http://caniuse.com/#feat=urlsearchparams for support for the `URLSearchParams` interface; I would *assume* (though I'm not 100% certain) that the browsers in red there are exactly the browsers for which `URL` objects will not have the `.searchParams` property. Importantly, Edge still does not have support. – Mark Amery Feb 25 '17 at 23:04
  • 1
    From the documentation: "Note that using a URLSearchParams instance is deprecated; soon browsers will just use a USVString for the init." source: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/URLSearchParams – pakman May 16 '18 at 23:52
  • @pakman I don't think those docs are up to date. The `init` [can be an object containing key/value pairs](https://url.spec.whatwg.org/#urlsearchparams) (as shown here). Perhaps the MDN docs are referring to passing in an instance of `URLSearchParams` as the parameter to an existing `URLSearchParams` – CodingIntrigue May 17 '18 at 12:49
  • 4
    `new URLSearchParams` doesn't seem to work correctly with `Array` properties. I expected it to convert the property `array: [1, 2]` to `array[]=1&array[]=2`, but converted it to `array=1,2`. Manually using the `append` method of it does result in `array=1&array=2`, but I would have to iterate over params object, and do that only for array types, not very ergonomic. – Guido Tarsia Mar 07 '19 at 17:33
  • @erandros The MDN docs do say that only USVString is a valid type to pass to URLSearchParms as constructor argument and since that seems to be a valid query string it is no use to try and pass anything to the constructor to get a valid query string. You can try the following: `var pr = new URLSearchParams(); [['a',1],['a',2]].forEach( ([key,val])=>pr.append(key,val) ); pr.toString()` – HMR Feb 27 '20 at 09:32
  • @HMR Not sure where you are seeing that, but MDN docs state that `init` can be: "A USVString instance, a URLSearchParams instance, a sequence of USVStrings, or a record containing USVStrings" – CodingIntrigue Feb 27 '20 at 10:19
  • @CodingIntrigue I read `soon browsers will just use a USVString for the init. `, for now `new URLSearchParams([['a':1],['a':2]])` will work but for how long? – HMR Feb 27 '20 at 10:23
  • @HMR I queried this statement with the editor at MDN. I hope it is not correct! – CodingIntrigue Feb 27 '20 at 11:06
  • 1
    It was indeed added in error :) https://github.com/mdn/sprints/issues/2856 – CodingIntrigue Feb 27 '20 at 11:39
  • `URL` is now a global in nodejs since v10.0.0: https://nodejs.org/api/url.html – marksyzm May 19 '20 at 10:57
  • `new URL('/relative/url')` throwing an error: Failed to construct 'URL': Invalid URL – Sergey Nudnov Jan 25 '22 at 02:43
  • @SergeyNudnov The `URL` constructor accepts two arguments. The second one is to provide an absolute base URL for the relative URL provided in the first argument. – Sebastian Simon Apr 20 '22 at 07:50
47
let params = {
  "param1": "value1",
  "param2": "value2"
};

let query = Object.keys(params)
             .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k]))
             .join('&');

let url = 'https://example.com/search?' + query;

fetch(url)
  .then(data => data.text())
  .then((text) => {
    console.log('request succeeded with JSON response', text)
  }).catch(function (error) {
    console.log('request failed', error)
  });
Sudharshan
  • 3,634
  • 2
  • 27
  • 27
  • do you need to encode the key? i've never done that. – chovy Sep 29 '21 at 04:34
  • 1
    @chovy - you do if your key contains special characters, like "&". Most of the time it won't, but sometimes it can. – Scotty Jamison Oct 30 '21 at 23:20
  • NOTE: encodeURIComponent can give bad results, e.g. it'll incorrectly encode a space as "%20" instead of "+" - this behavior is fine when you're percent encoding, for example, a URL's path (an intended use case), but query parameters are generally form-encoded, which follows an older version of the percent-encoding specification - you can use [URLSearchParams()](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) to properly encode/decode query parameters. See [this S.O. question](https://stackoverflow.com/questions/1634271/url-encoding-the-space-character-or-20) to learn more. – Scotty Jamison Dec 24 '21 at 20:30
33

As already answered, this is per spec not possible with the fetch-API, yet. But I have to note:

If you are on node, there's the querystring package. It can stringify/parse objects/querystrings:

var querystring = require('querystring')
var data = { key: 'value' }
querystring.stringify(data) // => 'key=value'

...then just append it to the url to request.


However, the problem with the above is, that you always have to prepend a question mark (?). So, another way is to use the parse method from nodes url package and do it as follows:

var url = require('url')
var data = { key: 'value' }
url.format({ query: data }) // => '?key=value'

See query at https://nodejs.org/api/url.html#url_url_format_urlobj

This is possible, as it does internally just this:

search = obj.search || (
    obj.query && ('?' + (
        typeof(obj.query) === 'object' ?
        querystring.stringify(obj.query) :
        String(obj.query)
    ))
) || ''
yckart
  • 32,460
  • 9
  • 122
  • 129
13

You can use stringify from query-string.

import { stringify } from 'query-string';

fetch(`https://example.org?${stringify(params)}`)
Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Hirurg103
  • 4,783
  • 2
  • 34
  • 50
9

encodeQueryString — encode an object as querystring parameters

/**
 * Encode an object as url query string parameters
 * - includes the leading "?" prefix
 * - example input — {key: "value", alpha: "beta"}
 * - example output — output "?key=value&alpha=beta"
 * - returns empty string when given an empty object
 */
function encodeQueryString(params) {
    const keys = Object.keys(params)
    return keys.length
        ? "?" + keys
            .map(key => encodeURIComponent(key)
                + "=" + encodeURIComponent(params[key]))
            .join("&")
        : ""
}

encodeQueryString({key: "value", alpha: "beta"})
 //> "?key=value&alpha=beta"
ChaseMoskal
  • 7,151
  • 5
  • 37
  • 50
8

I know this is stating the absolute obvious, but I feel it's worth adding this as an answer as it's the simplest of all:

const orderId = 1;
fetch('http://myapi.com/orders?order_id=' + orderId);
Evert
  • 93,428
  • 18
  • 118
  • 189
  • 13
    It's worth qualifying that this only works reliably with integer types. If you use strings, especially user-supplied ones (like search criteria) then you have to escape the string, otherwise you can get odd results if characters like `/`, `+` or `&` appear in the string. – Malvineous Apr 26 '18 at 03:26
  • Using the Request object can help, especially if you want to use a function to build the request and then hand that to the fetch() call, but I don't think using it is "absolute obvious". Also, the url should not be specified in the object literal of config options; it should be passed separately as the 1st parameter to the Request constructor (https://developer.mozilla.org/en-US/docs/Web/API/Request/Request). – Gen1-1 May 22 '20 at 19:14
  • @Gen1-1, ty. Made some edits. My sample was based on OP's snippet, but I simplified it a bit. – Evert Jan 07 '21 at 20:48
5

Maybe this is better:

const withQuery = require('with-query');

fetch(withQuery('https://api.github.com/search/repositories', {
  q: 'query',
  sort: 'stars',
  order: 'asc',
}))
.then(res => res.json())
.then((json) => {
  console.info(json);
})
.catch((err) => {
  console.error(err);
});
Bin HOU
  • 71
  • 1
  • 2
5

Solution without external packages

to perform a GET request using the fetch api I worked on this solution that doesn't require the installation of packages.

this is an example of a call to the google's map api

// encode to scape spaces
const esc = encodeURIComponent;
const url = 'https://maps.googleapis.com/maps/api/geocode/json?';
const params = { 
    key: "asdkfñlaskdGE",
    address: "evergreen avenue",
    city: "New York"
};
// this line takes the params object and builds the query string
const query = Object.keys(params).map(k => `${esc(k)}=${esc(params[k])}`).join('&')
const res = await fetch(url+query);
const googleResponse = await res.json()

feel free to copy this code and paste it on the console to see how it works!!

the generated url is something like:

https://maps.googleapis.com/maps/api/geocode/json?key=asdkf%C3%B1laskdGE&address=evergreen%20avenue&city=New%20York

this is what I was looking before I decided to write this, enjoy :D

Carlos
  • 3,480
  • 1
  • 16
  • 14
5

You can set params on your URL's searchParams:

const url = new URL('http://myapi.com/orders');
url.searchParams.set('order_id', '1');
fetch(url);

This has the advantage of building a request explicitly while allowing the original URL to be in any valid format.

Nick McCurdy
  • 17,658
  • 5
  • 50
  • 82
  • I tested it in Firefox before making my comment and it didn’t work. – Quentin Mar 15 '23 at 07:16
  • 1
    Here is a [live demo on JSBin](https://jsbin.com/gavirekawu/1/edit?js,console) in which I replace `fetch` with `console.log`. It logs the original URL from line one without the query string you attempt to add on line two when I test in Firefox, Safari, or Chrome. – Quentin Mar 15 '23 at 07:18
  • For multiple query params const searchParams = new URLSearchParams({ one : '1' , two : '2' }); const url = new URL(`${process.env.API_URL}/messages?${searchParams.toString()}`); fetch(url); – Pash Aug 19 '23 at 15:03
1

Template literals are also a valid option here, and provide a few benefits.

You can include raw strings, numbers, boolean values, etc:

    let request = new Request(`https://example.com/?name=${'Patrick'}&number=${1}`);

You can include variables:

    let request = new Request(`https://example.com/?name=${nameParam}`);

You can include logic and functions:

    let request = new Request(`https://example.com/?name=${nameParam !== undefined ? nameParam : getDefaultName() }`);

As far as structuring the data of a larger query string, I like using an array concatenated to a string. I find it easier to understand than some of the other methods:

let queryString = [
  `param1=${getParam(1)}`,
  `param2=${getParam(2)}`,
  `param3=${getParam(3)}`,
].join('&');

let request = new Request(`https://example.com/?${queryString}`, {
  method: 'GET'
});
Pat Kearns
  • 133
  • 8
  • 14
    You have to be very careful with this method because it does not URL-escape the strings first. So if you get a variable that contains a character like `+` or `&` then it won't work as expected and you'll end up with different parameters and values to what you thought. – Malvineous Apr 26 '18 at 03:30
-1

Was just working with Nativescript's fetchModule and figured out my own solution using string manipulation. Append the query string bit by bit to the url. Here is an example where query is passed as a json object (query = {order_id: 1}):

function performGetHttpRequest(fetchLink='http://myapi.com/orders', query=null) {
    if(query) {
        fetchLink += '?';
        let count = 0;
        const queryLength = Object.keys(query).length;
        for(let key in query) {
            fetchLink += key+'='+query[key];
            fetchLink += (count < queryLength) ? '&' : '';
            count++;
        }
    }
    // link becomes: 'http://myapi.com/orders?order_id=1'
    // Then, use fetch as in MDN and simply pass this fetchLink as the url.
}

I tested this over a multiple number of query parameters and it worked like a charm :) Hope this helps someone.

Amjad Abujamous
  • 736
  • 9
  • 9
  • 2
    This is a good example of why you should use 3rd party libs - your code might be working fine, but someone already did it much better – refaelio Jul 15 '20 at 15:19
  • This has the same drawbacks as [the answer by Evert](/a/43485348/4642212) and [the one by Pat Kearns](/a/46496234/4642212) already provided more than two years earlier. _“I tested this over a multiple number of query parameters and it worked like a charm”_ — You didn’t test this with anything relevant, then. [URLs](//en.wikipedia.org/wiki/URL#Syntax) have a syntax that can be tokenized on specific characters. Trying any of these characters in your function should make it obvious that this code is broken. – Sebastian Simon Apr 20 '22 at 08:12
  • @SebastianSimon Two years later, I stand corrected. Thank you my friend. – Amjad Abujamous Apr 25 '22 at 22:21
-1
const query = {
    is_active: true,
};

let url = `${apiUrl}/<endPoint>`;

const searchParams = Object.keys(query).length ? new URLSearchParams(query).toString() : null;

if (searchParams) {url = `${url}?${searchParams}`}

for nextJs 13+

const response = await fetch(url, {
  method: "GET",
  next: {
    // revalidate will be after 4 min
    revalidate: 240,
  },
  // cache: "no-cache",
});
-10

var paramsdate=01+'%s'+12+'%s'+2012+'%s';

request.get("https://www.exampleurl.com?fromDate="+paramsDate;