What is the best approach to adjusting parameters in a query string in a safe and reliable manner?
There is a fantastic native URLSearchParams API that can aid with this. Unfortunately, at the time of this post, it is not supported by some browsers (dang it, IE11). However, if the browsers you are developing for are supported, I would recommend this solution over the others we'll go over.
import querystring from 'querystring';
const adjustQueryParams = (str, { add = [], remove = [] } = {}) => {
const qs = querystring.parse(str.replace(/\?/g, "");
const params = [];
for (const [key, value] of Object.entries(qs)) {
if (!remove.includes(key)) {
params.push(`${key}=${value}`);
}
}
return [ ...params, ...add ].join('&');
};
Special thanks to one of my colleagues for helping improve the first iteration of the utility to be more reusable and extensible.
Here, we are using the querystring package to handle parsing the existing query string.
My first inclination was to create my own regex that would divvy up the query parameters into some sort of data structure. However, I felt wary towards this approach because I know that I could very easily miss some edge cases.
Furthermore, the package supports Internet Explorer. Yay!
Simple example of how querystring
would be used:
querystring.parse("env=prod&debug=false"); // { env: "prod", debug: "false" }
We are removing all instances of "?" before parsing (str.replace(/\?/g, "")
) since most query strings begin with a "?" (window.location.search
). This would cause the first key to contain a "?" ({ ?env: "prod" }
).
We then iterate through the parsed object containing the query parameters using the for...of loop, array destructuring, and Object.entries().
// qs = { env: "prod", debug: "false" }
for (const [key, value] of Object.entries(qs)) {
// First iteration: key = "env", value = "prod"
// Second iteration: key = "debug", value = "false"
}
We then check if the current key
is in the list of query parameters to remove (remove
) using Array.includes(). If it is not in the removal list, add the formatted query parameter to the params
array.
if (!remove.includes(key)) {
params.push(`${key}=${value}`);
}
Continuing with our example and if remove = ['debug']
, params
would equal ['env=prod']
.
At the end, we push on any query parameters we want added and join all the query parameters with an "&":
return [ ...params, ...add ].join('&');
For instance,
// params = ['env=prod']
// add = ['track=true', 'notifications=false']
[ ...params, ...add ].join('&') // 'env=prod&track=true¬ifications=false'
If you wanted to update the query string in the URL, a possible solution could use the above approach on the window.location.search string and then applying it with window.history.replaceState().