How to pass url query params?
For eg: http://www.abx.com?x=2&y=3
The fetch() operation simply uses the exact URL string as it was given. To pass the URL query params, simply have them in the URL string as in our example above:
fetch("http://www.abx.com?x=2&y=3")
If you need to construct query param string from a hash and you use jQuery on your site, you can do:
var url = "http://www.abx.com?" + $.param({foo: "bar", baz: "kuuq"})
fetch(url)
Update: here is what the fetch standard recommends in their documentation (also see discussion in https://github.com/whatwg/fetch/issues/56):
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(...)
This requires that the browser implements url.searchParams. A polyfill might be needed for older browsers.
Past discussions in #153 and #167.
If fetch is hoping to become a front runner as new technology to use it really should provide something as simple as accepting an object as a query string.
fetch('url.com', { qs: { a: 1, b: 2 } }) is pretty basic functionality offered by every other URI request technologies.
lack of structured get parameters is a rather curious decision on part of fetch - and not supporting it is a backwards step. As post above mentioned, every http request generation library has it, for valid reasons.
closing this ticket and other related without a solution is counterproductive.
Also curious can we have this feature?
I'm using this http://stackoverflow.com/a/34209399/707580
var params = {
parameter1: 'value_1',
parameter2: 'value 2',
parameter3: 'value&3'
};
var esc = encodeURIComponent;
var query = Object.keys(params)
.map(k => esc(k) + '=' + esc(params[k]))
.join('&');
@hbrls Thanks that worked for me. But the point here is to add the functionality so that fellow users can use fetch more easily
@oeddyo We would have added this feature if it was in the fetch spec, but it isn't. We won't implement non-standard features in this library, since that would differ compared to browser implementations in Chrome, Firefox, and lately Safari and IE.
You can add in this feature yourself with something like this:
export function fetch2(url, options={}) {
options = {
// your default options
credentials: 'same-origin',
redirect: 'error',
...options,
};
if(options.queryParams) {
url += (url.indexOf('?') === -1 ? '?' : '&') + queryParams(options.queryParams);
delete options.queryParams;
}
return fetch(url, options);
}
function queryParams(params) {
return Object.keys(params)
.map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k]))
.join('&');
}
Here's a little API whip up from these comments as an ES6 export
function getQueryString(params) {
var esc = encodeURIComponent;
return Object.keys(params)
.map(k => esc(k) + '=' + esc(params[k]))
.join('&');
}
function request(params) {
var method = params.method || 'GET';
var qs = '';
var body;
var headers = params.headers || {
'Accept': 'application/json',
'Content-Type': 'application/json',
};
if (['GET', 'DELETE'].indexOf(method) > -1)
qs = '?' + getQueryString(params.data);
else // POST or PUT
body = JSON.stringify(params.data);
var url = params.url + qs;
return fetch(url, { method, headers, body });
}
export default {
get: params => request(Object.assign({ method: 'GET' }, params)),
post: params => request(Object.assign({ method: 'POST' }, params)),
put: params => request(Object.assign({ method: 'PUT' }, params)),
delete: params => request(Object.assign({ method: 'DELETE' }, params))
};
So you'd use it like so:
var soFetch = require('./soFetch');
soFetch.get({ url: 'https://sumpin', data: { })
.then(response => console.log(response.json()));
How about if we have an array in params?
I think this can be a solution:
function getQueryString(params) {
return 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('&')
}
How about https://www.npmjs.com/package/jquery-param ?
I recommend this snippet from https://fetch.spec.whatwg.org/:
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(/* … */)
Example function with optional params argument:
const suchFetch = (path, fetchOpts, params) => {
var url = new URL(`${BASE_URL}${path}`)
if (params != null) Object.keys(params).forEach(key => url.searchParams.append(key, params[key]))
return fetch(url, fetchOpts)
.then((res) => res.json())
.catch((ex) => console.log("Fetch Exception", ex));
};
Our polyfill right now may handle URL instances incorrectly when passed to fetch() like in example above, but I'm making a fix to improve that.
What about instead of using a JSON object, one could use an instance of URLSearchParams? Wouldn't that work within the spec since it's supported as a body parameter?
@AaronHarris Yes, you can use an instance of URLSearchParams as a POST body. However, the discussion in this thread was about supplying query parameters within the URL for a GET request. GET requests can't have have bodies.
But URLSearchParams has a toString method, so you ought to be able to build a URL cheaply with that.
I don't know if there's a polyfill for that, or if it supports nested structures at all. You might be happier using the qs module.
@hbrls awesome workaround, but May we use the ES6 template strings instead of the '+' operator. haha
var params = {
parameter1: 'value_1',
parameter2: 'value 2',
parameter3: 'value&3'
};
var esc = encodeURIComponent;
var query = Object.keys(params)
.map(k => `${esc(k)}=${esc(params[k])}`)
.join('&');
I just created a small lib for it.
https://www.npmjs.com/package/with-query
You can just do it like this.
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);
});
This library parse and stringify the query string with full power of qs.
If it's a wrapper for qs, why not to use it directly?
@dkfiresky Absolutely not!
It uses qs only for parse and stringify the query string. It can also help you to dual with the original url that already has the query string and hash.
e.g.
// You may use a default query parameter in original url.
// `query` could be string or object
function searchRespositories(query) {
return fetch(withQuery('https://api.github.com/search/repositories?order=desc', query))
.then(res => res.json())
.then((json) => {
console.info(json);
})
.catch((err) => {
console.error(err);
});
}
searchRespositories({
q: 'query',
sort: 'stars',
order: 'asc',
})
Actually, out target is using this library in our project. The current code is
function getUserItems(req, options) {
const url = URL.format({
...URL.parse(`${baseURL}/v1.0/${userId}/items/${itemId}`),
query: options,
});
return fetch(url, {
headers: getRequiredHeaders(req),
});
}
After
function getUserItems(req, options) {
return fetch(withQuery(`${baseURL}/v1.0/${userId}/items/${itemId}`, options), {
headers: getRequiredHeaders(req),
});
}
just to chime in, I did this with this setup
import queryString from 'query-string'
fetch(`/some/url/path/?${queryString.stringify(params)}`)
This works in Chrome 58, haven't tested other versions/browsers:
const params = { a: 'foo', b: 'bar' };
const urlParams = new URLSearchParams(Object.entries(params));
fetch('/some/url?' + urlParams); // can use .toString() if you want to be explicit
Edit: can someone explain the downvotes? It's not an ideal solution, sure, but it uses a standard API, doesn't rely on an external library, and is essentially the same as what @od0 posted above, just a little terser and doesn't require an absolute URL like a URL object does. Browser compatibility is currently reasonable and it has polyfills available. It's also available in Node (very useful, for instance, if you need server+browser rendering support using isomorphic-fetch). Object.entries() is also pretty new, but again, compatibility isn't too bad (check here or here) and it's easily polyfillable.
Yes, query-string has a nicer API and it would be nice for fetch to have something built-in, all I'm doing is suggesting a built-in alternative for people that would prefer to stick to standards. If fetch ever does gain this functionality, URLSearchParams is probably what it will utilize.
// refer to above answers
const withQuery = (url, params) => {
let query = Object.keys(params)
.filter(k => params[k] !== undefined)
.map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k]))
.join('&');
url += (url.indexOf('?') === -1 ? '?' : '&') + query;
return url;
};
export default withQuery;
Edit: can someone explain the downvotes?
@noinkling It does not work with nested objects:
new URLSearchParams(Object.entries({foo: {bar: 'baz'}})).toString()
// => "foo=%5Bobject+Object%5D"
@lolmaus That's a legitimate concern, but the majority of the solutions suggested in this thread have the same issue because they're just covering the basic use case. Query string serialization of nested structures is generally considered an "advanced" feature (and there are are at least a few ways it can be done) - if it's needed, then a library is indeed likely the best bet (or just write your own function).
URLSearchParams does support values with the same key though, which could be used to the same effect with a bit more work.
I'm using https://medialize.github.io/URI.js , and am very happy with it.
Tried using the query-string package initially but it didn't seem to support nested objects, so switched to qs. That's working great so far.
I can't believe anyone would pretend fetch is a good standard for querying a backend without support for query parameters on GET. Why on earth wasn't this part of the standard from the beginning?
@sjatkins You can propose your feature ideas on the repo of the official spec (we're just a polyfill), but with url.searchParams being the preferred solution of spec authors, and because there is no unified standard of how an encoding mechanism of URI query parameters should work w.r.t. multiple values and nested keys, I don't think the whatwg-fetch spec is going to encompass an API for specifying query params anytime soon.
// https://fetch.spec.whatwg.org/#fetch-api
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(...)
Thank you everyone for sharing their solutions!
Most helpful comment
If fetch is hoping to become a front runner as new technology to use it really should provide something as simple as accepting an object as a query string.
fetch('url.com', { qs: { a: 1, b: 2 } })is pretty basic functionality offered by every other URI request technologies.