Генерация URL с параметрами на коленке и best practice

от автора

Как-то я увидел в проекте соседней команды код, который генерировал строку с URL-параметрами для последующей вставки в iframe src-атрибут.

Эта статья может показаться лишней, очевидной или слишком простой, но раз такое встречается в живой природе, об этом не стоит молчать, а наоборот, поделиться best-practices.

Итак, вот он, оригинальный код:

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'); };

Для справки, param1 и param2 в оригинальном коде имеют говорящие названия. А их значения могут быть любыми строками с множеством невалидных для URL символов

Какие проблемы у этого кода?

  • Во-первых, это отсутствие encodeURIComponent для каждого значения, которое вполне может содержать совершенно любые символы. (в контексте данной задачи эти названия задаются пользователями и могут содержать всевозможные знаки вроде амперсанда, пробелов или диакритических символов);
  • Во-вторых, это лишние пробелы и символы переноса строки, которые появляются из-за оператора template string `; Их автор данного кода пытается исправить с помощью метода .replace(), но этот подход ничего не решает;
  • В-третьих, это трудночитаемый и нерасширяемый код из-за выбранного синтаксиса, подверженный ошибкам.

Как их исправить?

Первый подход:

const delimiter = '&'; // выносим константу из области видимости функции 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; };

Что мы добились здесь? Код теперь выдает корректную строку. Лишних символов вроде переносов строки теперь нет, а все значения закодированы нативной функцией encodeURIComponent. А еще вынесли константу, теперь она не объявляется каждый раз как вызывается функция. Код стал чуточку чище.

Можно лучше? Можно! Второй подход:

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('&'); };

Мы избавились от константы. В данном контексте в этом нет ничего крамольного, так как оба символа — часть стандарта.

Теперь нет никаких повторяющихся строк, ручных конкатенаций. Заодно мы легко получили кодирование не только значения, но и ключа.

И еще разок

Обратим внимание на саму функцию и ее аргументы. Что, если нам понадобится больше аргументов? Нам надо будет их добавлять в конец функции, проставлять внутрь объекта queryParams. А затем вызывать функцию с этим новым новым аргументом. И так каждый раз, как добавится новый параметр. Перепишем функцию, и сделаем ее обобщенной:

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

Теперь функцию можно вынести в условный файл utils.js и использовать где угодно.

URLSearchParams

И тут на сцену выходит Web API. URLSearchParams нужен как раз в таких ситуациях.

И весь существующий код можно упростить до:

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

Ложкой дегтя является отсутствующая поддержка Internet Explorer, но мы всегда можем условно подключить полифилл, например, https://www.npmjs.com/package/url-search-params-polyfill .

Заключение

Если код кажется многословным, запутанным, то наверняка есть простые способы его улучшить.
А еще есть вероятность того, что нужная вам функциональность реализована на уровне Web API.

ссылка на оригинал статьи https://habr.com/ru/post/489888/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *