{"id":393168,"date":"2024-06-29T10:51:19","date_gmt":"2024-06-29T10:51:19","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=393168"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=393168","title":{"rendered":"<span>URL Search Params<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>Somehow I saw code in the project of a neighboring team that generated a string with URL parameters for subsequent insertion into the\u00a0<code>iframe<\/code>src attribute.<\/p>\n<p>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.<\/p>\n<p>So here it is, the original code:<\/p>\n<pre><code class=\"javascript\">const createQueryString = (param1, param2, objectId, timestamp, name) => {   const encodedTimestamp = encodeURIComponent(timestamp);   const delimiter = '&amp;';   const queryString = `${param1}${delimiter} param2=${param2}${delimiter} objectId=${objectId}${delimiter} itemTimestamp=${encodedTimestamp}${delimiter} itemName=${name}`;   return queryString.replace(\/ \/g, '%20'); }; <\/code><\/pre>\n<p><em>For reference,\u00a0<\/em><code>param1<\/code>and\u00a0<code>param2<\/code>in the original code have speaking names.\u00a0And their values \u200b\u200bcan be any strings with a lot of invalid URL characters<\/p>\n<h3>What are the problems with this code?<\/h3>\n<ul>\n<li>\n<p>Firstly, this is the absence\u00a0<code>encodeURIComponent<\/code>for each value, which may well contain absolutely any characters.\u00a0(in the context of this task, these names are user-defined and can contain all sorts of characters such as ampersands, spaces, or diacritics);<\/p>\n<\/li>\n<li>\n<p>Secondly, there are extra spaces and newlines that appear due to the\u00a0template string\u00a0<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Template_literals\" rel=\"noopener noreferrer nofollow\">operator<\/a><code>`<\/code>\u00a0;\u00a0The author of this code is trying to fix them using the method\u00a0<code>.replace()<\/code>, but this approach does not solve anything;<\/p>\n<\/li>\n<li>\n<p>Thirdly, it is difficult to read and non-extensible code due to the chosen syntax, prone to errors.<\/p>\n<\/li>\n<\/ul>\n<h3>How to fix them?<\/h3>\n<h4>First approach:<\/h4>\n<pre><code class=\"javascript\">const delimiter = '&amp;'; \/\/ 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; }; <\/code><\/pre>\n<p>What have we achieved here?\u00a0The code now produces the correct string.\u00a0There are no extra characters like line breaks now, and all values \u200b\u200bare encoded by the native function\u00a0<code>encodeURIComponent<\/code>.\u00a0And they also took out the constant, now it is not declared every time the function is called.\u00a0The code has become a little cleaner.<\/p>\n<h4>Can it be better?\u00a0Can!\u00a0Second approach:<\/h4>\n<pre><code class=\"javascript\">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('&amp;'); }; <\/code><\/pre>\n<p>We got rid of the constant.\u00a0In this context, there is nothing seditious about this, since both characters are part of the standard.<\/p>\n<p>Now there are no repeating strings, no manual concatenations.\u00a0At the same time, we easily got the encoding of not only the value, but also the key.<\/p>\n<h4>And one more time<\/h4>\n<p>Let&#8217;s pay attention to the function itself and its arguments.\u00a0What if we need more arguments?\u00a0We will need to add them to the end of the function, put them inside the\u00a0<code>queryParams<\/code>.\u00a0And then call the function with that new new argument.\u00a0And so every time a new parameter is added.\u00a0Let&#8217;s rewrite the function and make it generalized:<\/p>\n<pre><code class=\"javascript\">const encodeAndJoinPair = pair => pair   .map(encodeURIComponent)   .join('=');  const createQueryString = objectParams => Object   .entries(objectParams)   .map(encodeAndJoinPair)   .join('&amp;'); }; <\/code><\/pre>\n<p>Now the function can be moved to a conditional file\u00a0<code>utils.js<\/code>and used anywhere.<\/p>\n<h3>URLSearchParams<\/h3>\n<p>This is where the Web API comes into play.\u00a0<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/URLSearchParams\" rel=\"noopener noreferrer nofollow\">URLSearchParams is<\/a>\u00a0needed just in such situations.<\/p>\n<p>This package is a replacement for <code>qs<\/code> or <code>querystring<\/code> npm pacakges. It works with the majority of back-end query string parsers\/generators, it&#8217;s an internal browser API and also can be used in nodejs environment.<\/p>\n<p>And all existing code can be simplified to:<\/p>\n<pre><code class=\"javascript\">const createQueryString = objectParams => new URLSearchParams(objectParams).toString(); <\/code><\/pre>\n<p>A fly in the ointment is the missing support for Internet Explorer, but we can always conditionally include a polyfill, for example,\u00a0<a href=\"https:\/\/www.npmjs.com\/package\/url-search-params-polyfill\" rel=\"noopener noreferrer nofollow\">https:\/\/www.npmjs.com\/package\/url-search-params-polyfill<\/a>\u00a0.<\/p>\n<h3>Conclusion<\/h3>\n<p>If the code seems verbose, confusing, then there are probably simple ways to improve it.<br \/>And there is also the possibility that the functionality you need is implemented at the Web API level.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/654637\/\"> https:\/\/habr.com\/ru\/articles\/654637\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>Somehow I saw code in the project of a neighboring team that generated a string with URL parameters for subsequent insertion into the\u00a0<code>iframe<\/code>src attribute.<\/p>\n<p>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.<\/p>\n<p>So here it is, the original code:<\/p>\n<pre><code class=\"javascript\">const createQueryString = (param1, param2, objectId, timestamp, name) => {   const encodedTimestamp = encodeURIComponent(timestamp);   const delimiter = '&amp;';   const queryString = `${param1}${delimiter} param2=${param2}${delimiter} objectId=${objectId}${delimiter} itemTimestamp=${encodedTimestamp}${delimiter} itemName=${name}`;   return queryString.replace(\/ \/g, '%20'); }; <\/code><\/pre>\n<p><em>For reference,\u00a0<\/em><code>param1<\/code>and\u00a0<code>param2<\/code>in the original code have speaking names.\u00a0And their values \u200b\u200bcan be any strings with a lot of invalid URL characters<\/p>\n<h3>What are the problems with this code?<\/h3>\n<ul>\n<li>\n<p>Firstly, this is the absence\u00a0<code>encodeURIComponent<\/code>for each value, which may well contain absolutely any characters.\u00a0(in the context of this task, these names are user-defined and can contain all sorts of characters such as ampersands, spaces, or diacritics);<\/p>\n<\/li>\n<li>\n<p>Secondly, there are extra spaces and newlines that appear due to the\u00a0template string\u00a0<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Template_literals\" rel=\"noopener noreferrer nofollow\">operator<\/a><code>`<\/code>\u00a0;\u00a0The author of this code is trying to fix them using the method\u00a0<code>.replace()<\/code>, but this approach does not solve anything;<\/p>\n<\/li>\n<li>\n<p>Thirdly, it is difficult to read and non-extensible code due to the chosen syntax, prone to errors.<\/p>\n<\/li>\n<\/ul>\n<h3>How to fix them?<\/h3>\n<h4>First approach:<\/h4>\n<pre><code class=\"javascript\">const delimiter = '&amp;'; \/\/ 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; }; <\/code><\/pre>\n<p>What have we achieved here?\u00a0The code now produces the correct string.\u00a0There are no extra characters like line breaks now, and all values \u200b\u200bare encoded by the native function\u00a0<code>encodeURIComponent<\/code>.\u00a0And they also took out the constant, now it is not declared every time the function is called.\u00a0The code has become a little cleaner.<\/p>\n<h4>Can it be better?\u00a0Can!\u00a0Second approach:<\/h4>\n<pre><code class=\"javascript\">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('&amp;'); }; <\/code><\/pre>\n<p>We got rid of the constant.\u00a0In this context, there is nothing seditious about this, since both characters are part of the standard.<\/p>\n<p>Now there are no repeating strings, no manual concatenations.\u00a0At the same time, we easily got the encoding of not only the value, but also the key.<\/p>\n<h4>And one more time<\/h4>\n<p>Let&#8217;s pay attention to the function itself and its arguments.\u00a0What if we need more arguments?\u00a0We will need to add them to the end of the function, put them inside the\u00a0<code>queryParams<\/code>.\u00a0And then call the function with that new new argument.\u00a0And so every time a new parameter is added.\u00a0Let&#8217;s rewrite the function and make it generalized:<\/p>\n<pre><code class=\"javascript\">const encodeAndJoinPair = pair => pair   .map(encodeURIComponent)   .join('=');  const createQueryString = objectParams => Object   .entries(objectParams)   .map(encodeAndJoinPair)   .join('&amp;'); }; <\/code><\/pre>\n<p>Now the function can be moved to a conditional file\u00a0<code>utils.js<\/code>and used anywhere.<\/p>\n<h3>URLSearchParams<\/h3>\n<p>This is where the Web API comes into play.\u00a0<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/URLSearchParams\" rel=\"noopener noreferrer nofollow\">URLSearchParams is<\/a>\u00a0needed just in such situations.<\/p>\n<p>This package is a replacement for <code>qs<\/code> or <code>querystring<\/code> npm pacakges. It works with the majority of back-end query string parsers\/generators, it&#8217;s an internal browser API and also can be used in nodejs environment.<\/p>\n<p>And all existing code can be simplified to:<\/p>\n<pre><code class=\"javascript\">const createQueryString = objectParams => new URLSearchParams(objectParams).toString(); <\/code><\/pre>\n<p>A fly in the ointment is the missing support for Internet Explorer, but we can always conditionally include a polyfill, for example,\u00a0<a href=\"https:\/\/www.npmjs.com\/package\/url-search-params-polyfill\" rel=\"noopener noreferrer nofollow\">https:\/\/www.npmjs.com\/package\/url-search-params-polyfill<\/a>\u00a0.<\/p>\n<h3>Conclusion<\/h3>\n<p>If the code seems verbose, confusing, then there are probably simple ways to improve it.<br \/>And there is also the possibility that the functionality you need is implemented at the Web API level.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/654637\/\"> https:\/\/habr.com\/ru\/articles\/654637\/<\/a><br \/><\/br><\/br><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-393168","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/393168","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=393168"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/393168\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=393168"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=393168"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=393168"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}