Cleaner way of dealing with query params using URLSearchParams
20 Aug 2021
Ever had a situation where you are supposed to convert an object (key, values) into a query parameter and build a URL around it?
Here's an example:
let user = {
name: 'John Doe',
age: 24,
}
Let's say the URL that we want to build / API requires the fields of the above object to be as ?name=..&age=..
.
The most straightforward way of doing this would be looping through keys of the object
and manually appending the key/values to a String
while separating each value with an &
. Oh and don't forget to URL encode each value using encodeURIComponent
.
For example: John Doe
should be encoded as John%20Doe
or John+Doe
.
let obj = {
name: 'John Doe',
age: 24,
}
function buildQuery(obj) {
let query = ''
Object.entries(obj).forEach(([key, val], currentIndex, entries) => {
let keyValPair = `${key}=${encodeURIComponent(val)}`
if (currentIndex !== entries.length - 1) {
keyValPair += '&' // PS: Don't want URLs ending with '&' :)
}
query += keyValPair
})
return query
}
buildQuery(obj)
// Output: "name=John%20Doe&age=20"
You can implement the same with reduce
too:
function buildQuery(obj) {
return Object.entries(obj).reduce(
(query, [key, val], currentIndex, entries) => {
let keyValPair = query + `${key}=${encodeURIComponent(val)}`
if (currentIndex !== entries.length - 1) {
keyValPair += '&' // PS: Don't want URLs ending with '&' :)
}
return keyValPair
},
''
)
}
// Output: "name=John%20Doe&age=20"
There are other ways of doing this which are more or less similar.
But in my opinion, there's a much cleaner way of dealing with this problem. If you haven't read the title yet, it is by using URLSearchParams
function buildQuery(obj) {
let query = new URLSearchParams()
Object.entries(obj).forEach(([key, val]) => {
query.set(key, val)
})
return query.toString()
}
// Output: "name=John+Doe&age=20"
The set(key,val)
method in the URLSearchParams class sets/replaces the key and value into the query whereas append(key, val)
appends/adds the key/value into the query. You can use either of those based on the use case;
What about the other way round? What if I have a URL and I want to build an object out of the key/values you ask?
Yep, URLSearchParams has you covered. You can initialize the URLSearchParams constructor with a string i.e query params and loop over it using either forEach
loop or the classic for..of
loop.
let query = 'name=John%Doe&age=20'
function buildUser(query) {
let params = new URLSearchParams(query)
let user = {}
params.forEach((val, key) => {
user[key] = val
})
return user
}
// Output: {name: "John Doe", age: "20"}
URLSearchParams also comes with some handy utility functions like has
, get
, values
etc. I encourage you to look it up and read more about it.
Further Reading / References: