How to easily manipulate URL search parameters in JavaScript

In this article, I will explain cover how you can convert a query string into an object and vice versa, which will allow you to easily get and set URL query parameters.

Despite this being a common task, I find myself googling it repeatedly because there isn't only one way of doing it.

But before we start, what is a query string again?

A query string is the part of the URL that comes after the question mark.

When you google something, for instance, you can see your search query in the URL as a query parameter:

https://www.google.com/search?q=something

When working with URLs, parsing and creating these queries is a common task, which used to require a manual function that parses the string.

Nowadays, however, this is much easier thanks to the URLSearchParams interface, which we'll mainly use in this tutorial.

The browser support of this API is quite good as well. As you can see here, more than 95% of all users are covered.

How to create a query string

When making API requests, we'll typically need to append query parameters to the URL.

With the URLSearchParams API, we can simply pass an object with the parameters to the class's constructor:

const params = new URLSearchParams({ foo: "1", bar: "2" });

We can also pass an array with tuples or a query string.

With that done, we now have an instance of the URLSearchParams class. We can get the string version of this by calling toString and append this to our URL.

const query = params.toString(); // Output: foo=1&bar=2
const url = `https://thecatapi.com/?${query}`;

Building URLs with the URL constructor

Creating a URL is easier with the URL object constructor.

We can set the query to a URLSearchParams object; fetch also accepts this object instead of a string.

const url = new URL("https://thecatapi.com/");
// Equals "?breed=aegan&categories=sinks%2Cspace"
url.search = new URLSearchParams({
  breed: "aegan",
  categories: ["sinks", "space"],
});
const response = await fetch(url);

How to get URL parameters from a query string

Now, what can we do when we want to convert a query string into an object?

Let's say we have an entire URL from which we want to extract the query:

const urlString = "https://thecatapi.com/?breed=aegan&categories=sinks%2Cspace";

We can convert this into an URL object and access the URLSearchParams object via url.searchParams:

const urlString = "https://thecatapi.com/?breed=aegan&categories=sinks%2Cspace";
let url = new URL(urlString);
url.searchParams.get("breed"); // "aegan";

The URLSearchParams interface has some useful functions that allow us to extract data from the URL, such as get, getAll, keys, or has. You can read more about these functions on the MDN Web Docs.

While this should be enough in most cases, we might want to convert this into a regular object anyway.

Convert URLSearchParams to object

There are some use-cases where we'll need to have the search parameters in an object instead of the URLSearchParams interface.

This great StackOverflow answer helped me achieve this, so credit goes to the author. Give the answer an upvote if it helped you as well!

function paramsToObject(entries) {
  const result = {};
  for (const [key, value] of entries) {
    // each 'entry' is a [key, value] tupple
    result[key] = value;
  }
  return result;
}

This approach works well if we only have primitive values in our query string.

However, issues arise when we want to search queries with arrays.

Parsing URLs with arrays in the search query

Parsing URLs with arrays is a more complex topic because there is no standardized way of defining them in URLs, which means that the URLSearchParams API doesn't support parsing arrays or objects.

There's a massive number of implementations: Arrays can be defined by repeating the parameter...

?foo=bar&foo=qux

...with square brackets...

?foo[]=bar&foo[]=qux # URL-encoded: ?foo%5B%5D=bar&foo%5B%5D=qux

...or separated by a comma.

?foo=bar,qux

This article by Jonathan Stoikovitch explains this more in detail if you're curious.

Besides these formats mentioned, there are many more which I can't list here, as each API can implement its own syntax.

The take-away from this is that we either take it into our own hands and create a function that parses the search string according to the implementation, or we use a library that supports most cases (like query-string).

Here's an example of how such a function may look like, implementing the square bracket syntax (e.g. ?foo[]=a&foo[]=b):

const getQueryParams = (query) => {
  let params = {};
  new URLSearchParams(query).forEach((value, key) => {
    let decodedKey = decodeURIComponent(key);
    let decodedValue = decodeURIComponent(value);
    // This key is part of an array
    if (decodedKey.endsWith("[]")) {
      decodedKey = decodedKey.replace("[]", "");
      params[decodedKey] || (params[decodedKey] = []);
      params[decodedKey].push(decodedValue);
      // Just a regular parameter
    } else {
      params[decodedKey] = decodedValue;
    }
  });

  return params;
};

console.log(getQueryParams("?b[]=1&b[]=2&a=abc&c[]=1"));

Inspiration taken from this Gist.

{ b: [ '1', '2' ], a: 'abc', c: [ '1' ] }

Parsing other implementations would look similar, however, when dealing with multiple syntaxes, I would highly recommend using the query-string, as it's well-tested and supports most array implementations.

Conclusion

The URLSearchParams API is now well supported and offers the core functionality needed when manipulating search queries.

However, since objects and arrays are not standardized, it doesn't offer the functionality needed in all cases.

If your application has more advanced use-cases, you should consider using a library or creating your own function for parsing and creating query strings correctly.

If this article was helpful to you, make sure to subscribe to my newsletter to get notified when I release a new article on web development.

Support

PatreonKoFi