Pull to refresh

URL Search Params

Reading time3 min
Views5.2K
Original author: Pavel Shchegolev

Somehow I saw code in the project of a neighboring team that generated a string with URL parameters for subsequent insertion into the iframesrc attribute.

This article may seem superfluous, obvious or too simple, but since this occurs in wildlife, you should not be silent about it, but rather share best-practices.

So here it is, the original code:

const createQueryString = (param1, param2, objectId, timestamp, name) => {
  const encodedTimestamp = encodeURIComponent(timestamp);
  const delimiter = '&';
  const queryString = `${param1}${delimiter}
		param2=${param2}${delimiter}
		objectId=${objectId}${delimiter}
		itemTimestamp=${encodedTimestamp}${delimiter}
		itemName=${name}`;
  return queryString.replace(/ /g, '%20');
};

For reference, param1and param2in the original code have speaking names. And their values ​​can be any strings with a lot of invalid URL characters

What are the problems with this code?

  • Firstly, this is the absence encodeURIComponentfor each value, which may well contain absolutely any characters. (in the context of this task, these names are user-defined and can contain all sorts of characters such as ampersands, spaces, or diacritics);

  • Secondly, there are extra spaces and newlines that appear due to the template string operator` ; The author of this code is trying to fix them using the method .replace(), but this approach does not solve anything;

  • Thirdly, it is difficult to read and non-extensible code due to the chosen syntax, prone to errors.

How to fix them?

First approach:

const delimiter = '&'; // move up the constant out of the function scope
const createQueryString = (param1, param2, objectId, timestamp, name) => {
  const queryString = [
    `param1=${encodeURIComponent(param1)}`,
    `param2=${encodeURIComponent(param2)}`,
    `objectId=${encodeURIComponent(objectId)}`,
    `itemTimestamp=${encodeURIComponent(timestamp)}`,
    `itemName=${encodeURIComponent(name)}`
  ].join(delimeter);
  return queryString;
};

What have we achieved here? The code now produces the correct string. There are no extra characters like line breaks now, and all values ​​are encoded by the native function encodeURIComponent. And they also took out the constant, now it is not declared every time the function is called. The code has become a little cleaner.

Can it be better? Can! Second approach:

const createQueryString = (param1, param2, objectId, timestamp, name) => {
  const queryParams = {
     param1,
     param2,
     objectId,
     itemTimestamp: timestamp,
     itemName: name
  };
  const encodeAndJoinPair = pair => pair.map(encodeURIComponent).join('=');
  return Object.entries(queryParams).map(encodeAndJoinPair).join('&');
};

We got rid of the constant. In this context, there is nothing seditious about this, since both characters are part of the standard.

Now there are no repeating strings, no manual concatenations. At the same time, we easily got the encoding of not only the value, but also the key.

And one more time

Let's pay attention to the function itself and its arguments. What if we need more arguments? We will need to add them to the end of the function, put them inside the queryParams. And then call the function with that new new argument. And so every time a new parameter is added. Let's rewrite the function and make it generalized:

const encodeAndJoinPair = pair => pair
  .map(encodeURIComponent)
  .join('=');

const createQueryString = objectParams => Object
  .entries(objectParams)
  .map(encodeAndJoinPair)
  .join('&');
};

Now the function can be moved to a conditional file utils.jsand used anywhere.

URLSearchParams

This is where the Web API comes into play. URLSearchParams is needed just in such situations.

This package is a replacement for qs or querystring npm pacakges. It works with the majority of back-end query string parsers/generators, it's an internal browser API and also can be used in nodejs environment.

And all existing code can be simplified to:

const createQueryString = objectParams => new URLSearchParams(objectParams).toString();

A fly in the ointment is the missing support for Internet Explorer, but we can always conditionally include a polyfill, for example, https://www.npmjs.com/package/url-search-params-polyfill .

Conclusion

If the code seems verbose, confusing, then there are probably simple ways to improve it.
And there is also the possibility that the functionality you need is implemented at the Web API level.

Tags:
Hubs:
Rating0
Comments0

Articles