Skip to content

Instantly share code, notes, and snippets.

@davidfloyd91
Created August 25, 2021 03:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davidfloyd91/8c51c0f55fc28800ad3e664bc526387f to your computer and use it in GitHub Desktop.
Save davidfloyd91/8c51c0f55fc28800ad3e664bc526387f to your computer and use it in GitHub Desktop.
Build a query param string
/*
This function is meant to deal with lots of nonsense.
Ideally it would enjoy something like the following:
buildQueryParamString(['cool', 'okay'], '');
> "?cool&okay"
buildQueryParamString([['nifty', 'false'], ['neat', 'true']], '');
> "?nifty=false&neat=true"
buildQueryParamString([['wow', 'goodJob']], '?alreadyGotStarted=sureDid');
> "?alreadyGotStarted=sureDid&wow=goodJob"
If you give something like this it'll be alright. Or it'll do its best:
buildQueryParamString([['why', 'though', 100000, { okay: 'great' }]], 'bler???rrrr');
> "?why=though"
This'll make it pretty sad though:
buildQueryParamString(['que?ti&n', [{ hehe: 'evil' }, [undefined]]], '');
> "?que?ti&n&[object Object]="
So don't do that please.
*/
const buildQueryParamString = (paramsToAdd = [], builtString = '') => {
const builtStringLength = builtString.length;
const builtStringIsValid = builtStringLength && builtString[0] === '?';
// the first argument isn't an array or is empty
if (!Array.isArray(paramsToAdd) || !paramsToAdd?.length) {
// return second argument, if valid, or '?'
return builtStringIsValid ? builtString : '?';
}
let builtStringAndDelimiter;
// discard second argument if invalid
if (!builtStringIsValid) {
builtStringAndDelimiter = '?';
} else {
// decide whether to add '&'
const lastCharacter = builtString[builtStringLength - 1];
const needsDelimiter = lastCharacter !== '?' && lastCharacter !== '&';
const delimiter = needsDelimiter ? '&' : '';
builtStringAndDelimiter = `${builtString}${delimiter}`;
}
// is the next one 'oneOfThese' or ['one', 'ofThese']?
const nextParamRaw = paramsToAdd[0];
const nextParamIsKeyValuePair = Array.isArray(nextParamRaw) && nextParamRaw.length > 1;
// 'oneOfThese' or 'one=ofThese'
const nextParam = nextParamIsKeyValuePair ? `${nextParamRaw[0]}=${nextParamRaw[1]}` : nextParamRaw;
// '?oldStuff&oneOfThese' or '?oldStuff&one=ofThese'
const newBuiltString = `${builtStringAndDelimiter}${nextParam}`;
// we're done
if (paramsToAdd.length === 1) {
return newBuiltString;
}
// we're not -- recurse! 🌀
return buildQueryParamString(paramsToAdd.slice(1), newBuiltString);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment