I was looking for a similar JavaScript method for http_build_query
but did not find but create my own and here I am a bit confused to decide the right approach.
Here is the problem. I have an object of params and need to create query string to append with URL with help of encodeURIComponent
:
const params = {
"name": ["alpha &", "beta"],
"id": ["one", "&two=2"],
"from": 1533735971000,
"to": 1533822371147,
"status": true
};
Now there are two approaches when there is an array of strings are there. I name them pre-encode
and post-encode
for now.
pre-encode
Apply encodeURIComponent
to individual items and then join all items.
const params = {
"name": ["alpha &", "beta"],
"id": ["one", "&two=2"],
"from": 1533735971000,
"to": 1533822371147,
"status": true
};
const output = Object.entries(params).map((pair) => {
const [key, val] = pair;
if (val instanceof Array && val.length > 0) {
let pre_encode = val.map(encodeURIComponent).join(',');
console.log({pre_encode});
const pre_qs = `${encodeURIComponent(key)}=${pre_encode}`;
console.log({pre_qs})
return pre_qs;
} else {
return pair.map(encodeURIComponent).join('=');
}
}).join('&');
console.log({output});
Output
"name=alpha%20%26,beta&id=one,%26two%3D2&from=1533735971000&to=1533822371147&status=true"
post-encode
First, join all items then apply encodeURIComponent
.
const params = {
"name": ["alpha &", "beta"],
"id": ["one", "&two=2"],
"from": 1533735971000,
"to": 1533822371147,
"status": true
};
const output = Object.entries(params).map((pair) => {
const [key, val] = pair;
if (val instanceof Array && val.length > 0) {
let post_encode = encodeURIComponent(val.join(','));
console.log({post_encode});
const post_qs = `${encodeURIComponent(key)}=${post_encode}`;
console.log({post_qs})
return post_qs;
} else {
return pair.map(encodeURIComponent).join('=');
}
}).join('&');
console.log({output});
Output
"name=alpha%20%26%2Cbeta&id=one%2C%26two%3D2&from=1533735971000&to=1533822371147&status=true"
Which approach is the more efficient and right and how to handle null and undefined values?
1 Answer 1
Your main question
I have trouble understanding it, because:
- minor reason:
(unless I'm missing something obvious) whatever way you encode the array parts, the resulting query string is quite valid in both cases;
so the only possible criterion for choosing a method rather than the other one would be to find which one is faster... and this sounds a bit overkill! - major reason:
you initially referred to the PHPhttp_build_query()
function, so I'd expect you work the same, i.e. for a givenkey: [val_1, val_2]
:- you're currently returning
key=val_1,val_2
- while it should be
key=val_1&key=val_2
- you're currently returning
To match the latter case, I'd suggest something like this:
const output = Object.entries(params).map(
(pair) => {
let [key, val] = pair;
// normalize val to always an array
val = (val instanceof Array) ? val : [val];
// encode key only once
key = encodeURIComponent(key);
// then make a different query string for each val member
return val.map(
(member) => `${key}=${encodeURIComponent(member)}`
).join('&');
}
).join('&');
Your complementary question
To implement null or undefined, first you have to decide how they must be managed: they might be simply omitted, or included with no value (its often useful to have query params where only its presence/absence is meaningful for the underlying application).
Anyway you may simply add any of these capabilities; instead of
return val.map(
(member) => `${key}=${encodeURIComponent(member)}`
).join('&');
you can include null/undefined params simply with:
return val.map(
(member) => (member ? `${key}=${encodeURIComponent(member)}` : `${key}`)
).join('&');
(NOTE: it's up to you to enhance this with more precise tests if desired, in order to keep 0
as key=0
, or ''
as key=
)
or you can omit them with a slightly different method:
return val.reduce(
(result, member) => {
if (member) {
result.push(`${key}=${encodeURIComponent(member)}`);
}
return result;
},
[]
).join('&');
-
\$\begingroup\$ Thank you for the suggestions. I was using
.filter
to removenull
and undefined key and value prior to encoding. additionally using I need query inkey=val_1,val_2
format and I think that is right way instead of adding each key and value separately. isn't it. does server treat these bothkey=val1&key=val2
,key=val1,val2
as same or it depends on mechanism how they read the query params in my case BE is java? \$\endgroup\$xkeshav– xkeshav2018年08月11日 21:23:42 +00:00Commented Aug 11, 2018 at 21:23 -
1\$\begingroup\$ @pro.mean I can't say anything really pertinent about java. But you referred to PHP, and you can check that it's how it works. Subsequently I tend to think that it'd be the same with java, since browsers are necessarily agnostic with regard to server languages. In PHP, a query string like
key=val1&key=val2
is "rendered" inside of the$_GET
array as a member like'key' => ['val1', 'val2']
. \$\endgroup\$cFreed– cFreed2018年08月11日 23:28:42 +00:00Commented Aug 11, 2018 at 23:28 -
\$\begingroup\$
if (member)
does not preventnull
value \$\endgroup\$xkeshav– xkeshav2018年08月13日 06:53:38 +00:00Commented Aug 13, 2018 at 6:53 -
\$\begingroup\$ @pro.mean I must insist:
if (member)
preventsnull
,undefined
,0
, and''
(it's why I added a comment about the two latters). Tested! \$\endgroup\$cFreed– cFreed2018年08月13日 11:54:15 +00:00Commented Aug 13, 2018 at 11:54