Is there a fast and simple way to encode a JavaScript object into a string
that I can pass via a GET request?
No jQuery, no other frameworks—just plain JavaScript :)
Is there a fast and simple way to encode a JavaScript object into a string
that I can pass via a GET request?
No jQuery, no other frameworks—just plain JavaScript :)
Like this:
serialize = function(obj) {
var str = [];
for (var p in obj)
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
}
console.log(serialize({
foo: "hi there",
bar: "100%"
}));
// foo=hi%20there&bar=100%25
This one also converts recursive objects (using PHP "array" notation for the query string):
serialize = function(obj, prefix) {
var str = [],
p;
for (p in obj) {
if (obj.hasOwnProperty(p)) {
var k = prefix ? prefix + "[" + p + "]" : p,
v = obj[p];
str.push((v !== null && typeof v === "object") ?
serialize(v, k) :
encodeURIComponent(k) + "=" + encodeURIComponent(v));
}
}
return str.join("&");
}
console.log(serialize({
foo: "hi there",
bar: {
blah: 123,
quux: [1, 2, 3]
}
}));
// foo=hi%20there&bar%5Bblah%5D=123&bar%5Bquux%5D%5B0%5D=1&bar%5Bquux%5D%5B1%5D=2&bar%5Bquux%5D%5B2%5D=3
Just use URLSearchParams
This works in all current browsers
new URLSearchParams(object).toString()
jQuery has a function for this, jQuery.param(). If you're already using it, you can use this:
Example:
var params = { width:1680, height:1050 };
var str = jQuery.param( params );
str
now contains width=1680&height=1050
.
I suggest using the URLSearchParams
interface:
const searchParams = new URLSearchParams();
const params = {foo: "hi there", bar: "100%" };
Object.keys(params).forEach(key => searchParams.append(key, params[key]));
console.log(searchParams.toString())
Or by passing the search object into the constructor like this:
const params = {foo: "hi there", bar: "100%" };
const queryString = new URLSearchParams(params).toString();
console.log(queryString);
Use:
Object.keys(obj).reduce(function(a,k){a.push(k+'='+encodeURIComponent(obj[k]));return a},[]).join('&')
I like this one-liner, but I bet it would be a more popular answer if it matched the accepted answer semantically:
function serialize( obj ) {
let str = '?' + Object.keys(obj).reduce(function(a, k){
a.push(k + '=' + encodeURIComponent(obj[k]));
return a;
}, []).join('&');
return str;
}
Here's a one liner in ES6:
Object.keys(obj).map(k => `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`).join('&');
const querystring = require('querystring')
const obj = {
foo: 'bar',
baz: 'tor'
}
let result = querystring.stringify(obj)
// foo=bar&baz=tor
Reference: Query string
This method converts a JavaScript object into a URI query string. It also handles nested arrays and objects (in Ruby on Rails and PHP syntax):
function serializeQuery(params, prefix) {
const query = Object.keys(params).map((key) => {
const value = params[key];
if (params.constructor === Array)
key = `${prefix}[]`;
else if (params.constructor === Object)
key = (prefix ? `${prefix}[${key}]` : key);
if (typeof value === 'object')
return serializeQuery(value, key);
else
return `${key}=${encodeURIComponent(value)}`;
});
return [].concat.apply([], query).join('&');
}
Example Usage:
let params = {
a: 100,
b: 'has spaces',
c: [1, 2, 3],
d: { x: 9, y: 8}
}
serializeQuery(params)
// returns 'a=100&b=has%20spaces&c[]=1&c[]=2&c[]=3&d[x]=9&d[y]=8
A small amendment to the accepted solution by user187291:
serialize = function(obj) {
var str = [];
for(var p in obj){
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
}
return str.join("&");
}
Checking for hasOwnProperty on the object makes JSLint and JSHint happy, and it prevents accidentally serializing methods of the object or other stuff if the object is anything but a simple dictionary. See the paragraph on for statements on Code Conventions for the JavaScript Programming Language.
Here is a one-liner:
const encoded = Object.entries(obj).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join("&");
If you need to send arbitrary objects, then GET is a bad idea since there are limits to the lengths of URLs that user agents and web servers will accepts. My suggestion would be to build up an array of name-value pairs to send and then build up a query string:
function QueryStringBuilder() {
var nameValues = [];
this.add = function(name, value) {
nameValues.push( {name: name, value: value} );
};
this.toQueryString = function() {
var segments = [], nameValue;
for (var i = 0, len = nameValues.length; i < len; i++) {
nameValue = nameValues[i];
segments[i] = encodeURIComponent(nameValue.name) + "=" + encodeURIComponent(nameValue.value);
}
return segments.join("&");
};
}
var qsb = new QueryStringBuilder();
qsb.add("veg", "cabbage");
qsb.add("vegCount", "5");
alert( qsb.toQueryString() );
Here's the CoffeeScript version of the accepted answer.
serialize = (obj, prefix) ->
str = []
for p, v of obj
k = if prefix then prefix + "[" + p + "]" else p
if typeof v == "object"
str.push(serialize(v, k))
else
str.push(encodeURIComponent(k) + "=" + encodeURIComponent(v))
str.join("&")
A little bit look better
objectToQueryString(obj, prefix) {
return Object.keys(obj).map(objKey => {
if (obj.hasOwnProperty(objKey)) {
const key = prefix ? `${prefix}[${objKey}]` : objKey;
const value = obj[objKey];
return typeof value === "object" ?
this.objectToQueryString(value, key) :
`${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
}
return null;
}).join("&");
}
This one skips null/undefined values
export function urlEncodeQueryParams(data) {
const params = Object.keys(data).map(key => data[key] ? `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}` : '');
return params.filter(value => !!value).join('&');
}
Use:
const toQueryString = obj => "?".concat(Object.keys(obj).map(e => `${encodeURIComponent(e)}=${encodeURIComponent(obj[e])}`).join("&"));
const data = {
offset: 5,
limit: 10
};
toQueryString(data); // => ?offset=5&limit=10
const data = {
offset: 5,
limit: 10
};
new URLSearchParams(data).toString(); // => ?offset=5&limit=10
Both the above methods will set the value as null if not present. If you want not to set the query parameter if value is null then use:
const toQueryString = obj => "?".concat(Object.keys(obj).map(e => obj[e] ? `${encodeURIComponent(e)}=${encodeURIComponent(obj[e])}` : null).filter(e => !!e).join("&"));
const data = {
offset: null,
limit: 10
};
toQueryString(data); // => "?limit=10" else with above methods "?offset=null&limit=10"
You can freely use any method.
Here's a concise & recursive version with Object.entries. It handles arbitrarily nested arrays, but not nested objects. It also removes empty elements:
const format = (k,v) => v !== null ? `${k}=${encodeURIComponent(v)}` : ''
const to_qs = (obj) => {
return [].concat(...Object.entries(obj)
.map(([k,v]) => Array.isArray(v)
? v.map(arr => to_qs({[k]:arr}))
: format(k,v)))
.filter(x => x)
.join('&');
}
E.g.:
let json = {
a: [1, 2, 3],
b: [], // omit b
c: 1,
d: "test&encoding", // uriencode
e: [[4,5],[6,7]], // flatten this
f: null, // omit nulls
g: 0
};
let qs = to_qs(json)
=> "a=1&a=2&a=3&c=1&d=test%26encoding&e=4&e=5&e=6&e=7&g=0"
I have a simpler solution that does not use any third-party library and is already apt to be used in any browser that has "Object.keys" (aka all modern browsers + Edge + Internet Explorer):
In ES5:
function(a){
if( typeof(a) !== 'object' )
return '';
return `?${Object.keys(a).map(k=>`${k}=${a[k]}`).join('&')}`;
}
In ES3:
function(a){
if( typeof(a) !== 'object' )
return '';
return '?' + Object.keys(a).map(function(k){ return k + '=' + a[k] }).join('&');
}
I made a comparison of JSON stringifiers and the results are as follows:
JSON: {"_id":"5973782bdb9a930533b05cb2","isActive":true,"balance":"$1,446.35","age":32,"name":"Logan Keller","email":"logankeller@artiq.com","phone":"+1 (952) 533-2258","friends":[{"id":0,"name":"Colon Salazar"},{"id":1,"name":"French Mcneil"},{"id":2,"name":"Carol Martin"}],"favoriteFruit":"banana"}
Rison: (_id:'5973782bdb9a930533b05cb2',age:32,balance:'$1,446.35',email:'logankeller@artiq.com',favoriteFruit:banana,friends:!((id:0,name:'Colon Salazar'),(id:1,name:'French Mcneil'),(id:2,name:'Carol Martin')),isActive:!t,name:'Logan Keller',phone:'+1 (952) 533-2258')
O-Rison: _id:'5973782bdb9a930533b05cb2',age:32,balance:'$1,446.35',email:'logankeller@artiq.com',favoriteFruit:banana,friends:!((id:0,name:'Colon Salazar'),(id:1,name:'French Mcneil'),(id:2,name:'Carol Martin')),isActive:!t,name:'Logan Keller',phone:'+1 (952) 533-2258'
JSURL: ~(_id~'5973782bdb9a930533b05cb2~isActive~true~balance~'!1*2c446.35~age~32~name~'Logan*20Keller~email~'logankeller*40artiq.com~phone~'*2b1*20*28952*29*20533-2258~friends~(~(id~0~name~'Colon*20Salazar)~(id~1~name~'French*20Mcneil)~(id~2~name~'Carol*20Martin))~favoriteFruit~'banana)
QS: _id=5973782bdb9a930533b05cb2&isActive=true&balance=$1,446.35&age=32&name=Logan Keller&email=logankeller@artiq.com&phone=+1 (952) 533-2258&friends[0][id]=0&friends[0][name]=Colon Salazar&friends[1][id]=1&friends[1][name]=French Mcneil&friends[2][id]=2&friends[2][name]=Carol Martin&favoriteFruit=banana
URLON: $_id=5973782bdb9a930533b05cb2&isActive:true&balance=$1,446.35&age:32&name=Logan%20Keller&email=logankeller@artiq.com&phone=+1%20(952)%20533-2258&friends@$id:0&name=Colon%20Salazar;&$id:1&name=French%20Mcneil;&$id:2&name=Carol%20Martin;;&favoriteFruit=banana
QS-JSON: isActive=true&balance=%241%2C446.35&age=32&name=Logan+Keller&email=logankeller%40artiq.com&phone=%2B1+(952)+533-2258&friends(0).id=0&friends(0).name=Colon+Salazar&friends(1).id=1&friends(1).name=French+Mcneil&friends(2).id=2&friends(2).name=Carol+Martin&favoriteFruit=banana
The shortest among them is URL Object Notation.
There another popular library, qs. You can add it by:
yarn add qs
And then use it like this:
import qs from 'qs'
const array = { a: { b: 'c' } }
const stringified = qs.stringify(array, { encode: false })
console.log(stringified) //-- outputs a[b]=c
This is an addition for the accepted solution. This works with objects and array of objects:
parseJsonAsQueryString = function (obj, prefix, objName) {
var str = [];
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
var v = obj[p];
if (typeof v == "object") {
var k = (objName ? objName + '.' : '') + (prefix ? prefix + "[" + p + "]" : p);
str.push(parseJsonAsQueryString(v, k));
} else {
var k = (objName ? objName + '.' : '') + (prefix ? prefix + '.' + p : p);
str.push(encodeURIComponent(k) + "=" + encodeURIComponent(v));
//str.push(k + "=" + v);
}
}
}
return str.join("&");
}
Also I have added objName if you're using object parameters, like in ASP.NET MVC action methods.
A single line to convert an object into a query string in case somebody needs it again:
let Objs = { a: 'obejct-a', b: 'object-b' }
Object.keys(objs).map(key => key + '=' + objs[key]).join('&')
// The result will be a=object-a&b=object-b
In ES7, you can write this in one line:
const serialize = (obj) => (Object.entries(obj).map(i => [i[0], encodeURIComponent(i[1])].join('=')).join('&'))
const params = {
a: 1,
b: 'query stringify',
c: null,
d: undefined,
f: '',
g: { foo: 1, bar: 2 },
h: ['Winterfell', 'Westeros', 'Braavos'],
i: { first: { second: { third: 3 }}}
}
static toQueryString(params = {}, prefix) {
const query = Object.keys(params).map((k) => {
let key = k;
const value = params[key];
if (!value && (value === null || value === undefined || isNaN(value))) {
value = '';
}
switch (params.constructor) {
case Array:
key = `${prefix}[]`;
break;
case Object:
key = (prefix ? `${prefix}[${key}]` : key);
break;
}
if (typeof value === 'object') {
return this.toQueryString(value, key); // for nested objects
}
return `${key}=${encodeURIComponent(value)}`;
});
return query.join('&');
}
toQueryString(params)
"a=1&b=query%20stringify&c=&d=&f=&g[foo]=1&g[bar]=2&h[]=Winterfell&h[]=Westeros&h[]=Braavos&i[first][second][third]=3"
If you want to convert a nested object recursively and the object may or may not contain arrays (and the arrays may contain objects or arrays, etc), then the solution gets a little more complex. This is my attempt.
I've also added some options to choose if you want to record for each object member at what depth in the main object it sits, and to choose if you want to add a label to the members that come from converted arrays.
Ideally you should test if the thing parameter really receives an object or array.
function thingToString(thing,maxDepth,recordLevel,markArrays){
//thing: object or array to be recursively serialized
//maxDepth (int or false):
// (int) how deep to go with converting objects/arrays within objs/arrays
// (false) no limit to recursive objects/arrays within objects/arrays
//recordLevel (boolean):
// true - insert "(level 1)" before transcript of members at level one (etc)
// false - just
//markArrays (boolean):
// insert text to indicate any members that came from arrays
var result = "";
if (maxDepth !== false && typeof maxDepth != 'number') {maxDepth = 3;}
var runningDepth = 0;//Keeps track how deep we're into recursion
//First prepare the function, so that it can call itself recursively
function serializeAnything(thing){
//Set path-finder values
runningDepth += 1;
if(recordLevel){result += "(level " + runningDepth + ")";}
//First convert any arrays to object so they can be processed
if (thing instanceof Array){
var realObj = {};var key;
if (markArrays) {realObj['type'] = "converted array";}
for (var i = 0;i < thing.length;i++){
if (markArrays) {key = "a" + i;} else {key = i;}
realObj[key] = thing[i];
}
thing = realObj;
console.log('converted one array to ' + typeof realObj);
console.log(thing);
}
//Then deal with it
for (var member in thing){
if (typeof thing[member] == 'object' && runningDepth < maxDepth){
serializeAnything(thing[member]);
//When a sub-object/array is serialized, it will add one to
//running depth. But when we continue to this object/array's
//next sibling, the level must go back up by one
runningDepth -= 1;
} else if (maxDepth !== false && runningDepth >= maxDepth) {
console.log('Reached bottom');
} else
if (
typeof thing[member] == "string" ||
typeof thing[member] == 'boolean' ||
typeof thing[member] == 'number'
){
result += "(" + member + ": " + thing[member] + ") ";
} else {
result += "(" + member + ": [" + typeof thing[member] + " not supported]) ";
}
}
}
//Actually kick off the serialization
serializeAnything(thing);
return result;
}
This is a solution that will work for .NET backends out of the box. I have taken the primary answer of this thread and updated it to fit our .NET needs.
function objectToQuerystring(params) {
var result = '';
function convertJsonToQueryString(data, progress, name) {
name = name || '';
progress = progress || '';
if (typeof data === 'object') {
Object.keys(data).forEach(function (key) {
var value = data[key];
if (name == '') {
convertJsonToQueryString(value, progress, key);
} else {
if (isNaN(parseInt(key))) {
convertJsonToQueryString(value, progress, name + '.' + key);
} else {
convertJsonToQueryString(value, progress, name + '[' + key+ ']');
}
}
})
} else {
result = result ? result.concat('&') : result.concat('?');
result = result.concat(`${name}=${data}`);
}
}
convertJsonToQueryString(params);
return result;
}
It can handle recursive objects or arrays in the standard query form, like a=val&b[0]=val&b[1]=val&c=val&d[some key]=val
. Here's the final function.
const objectToQueryString = (initialObj) => {
const reducer = (obj, parentPrefix = null) => (prev, key) => {
const val = obj[key];
key = encodeURIComponent(key);
const prefix = parentPrefix ? `${parentPrefix}[${key}]` : key;
if (val == null || typeof val === 'function') {
prev.push(`${prefix}=`);
return prev;
}
if (['number', 'boolean', 'string'].includes(typeof val)) {
prev.push(`${prefix}=${encodeURIComponent(val)}`);
return prev;
}
prev.push(Object.keys(val).reduce(reducer(val, prefix), []).join('&'));
return prev;
};
return Object.keys(initialObj).reduce(reducer(initialObj), []).join('&');
};
const testCase1 = {
name: 'Full Name',
age: 30
}
const testCase2 = {
name: 'Full Name',
age: 30,
children: [
{name: 'Child foo'},
{name: 'Foo again'}
],
wife: {
name: 'Very Difficult to say here'
}
}
console.log(objectToQueryString(testCase1));
console.log(objectToQueryString(testCase2));
Expand the snippet below to verify the result in your browser -
const objectToQueryString = (initialObj) => {
const reducer = (obj, parentPrefix = null) => (prev, key) => {
const val = obj[key];
key = encodeURIComponent(key);
const prefix = parentPrefix ? `${parentPrefix}[${key}]` : key;
if (val == null || typeof val === 'function') {
prev.push(`${prefix}=`);
return prev;
}
if (['number', 'boolean', 'string'].includes(typeof val)) {
prev.push(`${prefix}=${encodeURIComponent(val)}`);
return prev;
}
prev.push(Object.keys(val).reduce(reducer(val, prefix), []).join('&'));
return prev;
};
return Object.keys(initialObj).reduce(reducer(initialObj), []).join('&');
};
const testCase1 = {
name: 'Full Name',
age: 30
}
const testCase2 = {
name: 'Full Name',
age: 30,
children: [
{name: 'Child foo'},
{name: 'Foo again'}
],
wife: {
name: 'Very Difficult to say here'
}
}
console.log(objectToQueryString(testCase1));
console.log(objectToQueryString(testCase2));
functions
, null
, and undefined
keys
and values
for empty objects and arrays.new Number(1)
or new String('my string')
because no one should ever do thatThe previous answers do not work if you have a lot of nested objects.
Instead you can pick the function parameter from jquery-param/jquery-param.js. It worked very well for me!
var param = function (a) {
var s = [], rbracket = /\[\]$/,
isArray = function (obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}, add = function (k, v) {
v = typeof v === 'function' ? v() : v === null ? '' : v === undefined ? '' : v;
s[s.length] = encodeURIComponent(k) + '=' + encodeURIComponent(v);
}, buildParams = function (prefix, obj) {
var i, len, key;
if (prefix) {
if (isArray(obj)) {
for (i = 0, len = obj.length; i < len; i++) {
if (rbracket.test(prefix)) {
add(prefix, obj[i]);
} else {
buildParams(prefix + '[' + (typeof obj[i] === 'object' ? i : '') + ']', obj[i]);
}
}
} else if (obj && String(obj) === '[object Object]') {
for (key in obj) {
buildParams(prefix + '[' + key + ']', obj[key]);
}
} else {
add(prefix, obj);
}
} else if (isArray(obj)) {
for (i = 0, len = obj.length; i < len; i++) {
add(obj[i].name, obj[i].value);
}
} else {
for (key in obj) {
buildParams(key, obj[key]);
}
}
return s;
};
return buildParams('', a).join('&').replace(/%20/g, '+');
};
ok, it's a older post but i'm facing this problem and i have found my personal solution.. maybe can help someone else..
function objToQueryString(obj){
var k = Object.keys(obj);
var s = "";
for(var i=0;i<k.length;i++) {
s += k[i] + "=" + encodeURIComponent(obj[k[i]]);
if (i != k.length -1) s += "&";
}
return s;
};
I've written a package just for that: object-query-string :)
It supports nested objects, arrays, custom encoding functions, etc. It is lightweight and jQuery-free.
// TypeScript
import { queryString } from 'object-query-string';
// Node.js
const { queryString } = require("object-query-string");
const query = queryString({
filter: {
brands: ["Audi"],
models: ["A4", "A6", "A8"],
accidentFree: true
},
sort: 'mileage'
});
returns
filter[brands][]=Audi&filter[models][]=A4&filter[models][]=A6&filter[models][]=A8&filter[accidentFree]=true&sort=milage
After going through some top answers here, I have wrote another implementation that tackles some edge cases as well
function serialize(params, prefix) {
return Object.entries(params).reduce((acc, [key, value]) => {
// remove whitespace from both sides of the key before encoding
key = encodeURIComponent(key.trim());
if (params.constructor === Array ) {
key = `${prefix}[]`;
} else if (params.constructor === Object) {
key = (prefix ? `${prefix}[${key}]` : key);
}
/**
* - undefined and NaN values will be skipped automatically
* - value will be empty string for functions and null
* - nested arrays will be flattened
*/
if (value === null || typeof value === 'function') {
acc.push(`${key}=`);
} else if (typeof value === 'object') {
acc = acc.concat(serialize(value, key));
} else if(['number', 'boolean', 'string'].includes(typeof value) && value === value) { // self-check to avoid NaN
acc.push(`${key}=${encodeURIComponent(value)}`);
}
return acc;
}, []);
}
function objectToQueryString(queryParameters) {
return queryParameters ? serialize(queryParameters).join('&'): '';
}
let x = objectToQueryString({
foo: 'hello world',
bar: {
blah: 123,
list: [1, 2, 3],
'nested array': [[4,5],[6,7]] // will be flattened
},
page: 1,
limit: undefined, // field will be ignored
check: false,
max: NaN, // field will be ignored
prop: null,
' key value': 'with spaces' // space in key will be trimmed out
});
console.log(x); // foo=hello%20world&bar[blah]=123&bar[list][]=1&bar[list][]=2&bar[list][]=3&bar[nested%20array][][]=4&bar[nested%20array][][]=5&bar[nested%20array][][]=6&bar[nested%20array][][]=7&page=1&check=false&prop=&key%20value=with%20spaces
/**
* Converts an object into a Cookie-like string.
* @param toSerialize object or array to be serialized
* @param prefix used in deep objects to describe the final query parameter
* @returns ampersand separated key=value pairs
*
* Example:
* ```js
* serialize({hello:[{world: "nice"}]}); // outputs "hello[0][world]=nice"
* ```
* ---
* Adapted to TS from a StackOverflow answer https://stackoverflow.com/a/1714899/4537906
*/
const serialize = (toSerialize: unknown = {}, prefix?: string) => {
const keyValuePairs = [];
Object.keys(toSerialize).forEach((attribute) => {
if (Object.prototype.hasOwnProperty.call(toSerialize, attribute)) {
const key = prefix ? `${prefix}[${attribute}]` : attribute;
const value = toSerialize[attribute];
const toBePushed =
value !== null && typeof value === "object"
? serialize(value, key)
: `${key}=${value}`;
keyValuePairs.push(toBePushed);
}
});
return keyValuePairs.join("&");
};
URLSearchParams looks good, but it didn't work for nested objects.
Try to use
encodeURIComponent(JSON.stringify(object))
Just another way (no recursive object):
getQueryString = function(obj)
{
result = "";
for(param in obj)
result += ( encodeURIComponent(param) + '=' + encodeURIComponent(obj[param]) + '&' );
if(result) //it's not empty string when at least one key/value pair was added. In such case we need to remove the last '&' char
result = result.substr(0, result.length - 1); //If length is zero or negative, substr returns an empty string [ref. http://msdn.microsoft.com/en-us/library/0esxc5wy(v=VS.85).aspx]
return result;
}
alert( getQueryString({foo: "hi there", bar: 123, quux: 2 }) );
Referring to the answer user187291, add "isArray" as a parameter to make the JSON nested array be converted.
data : {
staffId : "00000001",
Detail : [ {
"identityId" : "123456"
}, {
"identityId" : "654321"
} ],
}
To make the result,
staffId=00000001&Detail[0].identityId=123456&Detail[1].identityId=654321
use:
serialize = function(obj, prefix, isArray) {
var str = [], p = 0;
for (p in obj) {
if (obj.hasOwnProperty(p)) {
var k, v;
if (isArray)
k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
else
k = prefix ? prefix + "." + p + "" : p, v = obj[p];
if (v !== null && typeof v === "object") {
if (Array.isArray(v)) {
serialize(v, k, true);
} else {
serialize(v, k, false);
}
} else {
var query = k + "=" + v;
str.push(query);
}
}
}
return str.join("&");
};
serialize(data, "prefix", false);
Here is a simple implementation that gets an object and converts it to a query parameters string:
export function objectToQueryParams(queryParams: object): string {
return queryParams ?
Object.entries(queryParams).reduce((acc, [key, val], index) => {
const sign = index === 0 ? '?' : '&';
acc += `${sign}${encodeURIComponent(key)}=${encodeURIComponent(val)}`;
return acc;
}, '')
: '';
}
My implementation of encoding an object as a query string, using reduce
:
export const encodeAsQueryString = (params) => (
Object.keys(params).reduce((acc, key)=>(
params.hasOwnProperty(key) ? (
[...acc, encodeURIComponent(key) + '=' + encodeURIComponent(params[key])]
) : acc
), []).join('&')
);
If you want to pass an entire object as a single parameter, e.g, ?filter={param1: "val1", param2: "val2"}
:
const serializeObject = (obj) => {
let objStr = JSON.stringify(obj);
objStr = objStr.replace(/\{/g, encodeURIComponent("{"));
objStr = objStr.replace(/}/g, encodeURIComponent("}"));
objStr = objStr.replace(/:/g, encodeURIComponent(":"));
return objStr;
};
let res = serializeObject({param1: "val1", param2: "val2"});
console.log("serializeObject:", res); //%7B"param1"%3A"val1","param2"%3A"val2"%7D
console.log("serializeObject-decoded:", decodeURIComponent(res)); //{"param1":"val1","param2":"val2"}
Use:
const objectToQueryParams = (o = {}) =>
Object.entries(o)
.map((p) => `${encodeURIComponent(p[0])}=${encodeURIComponent(p[1])}`)
.join("&");
Refer to the below gist for more: https://gist.github.com/bhaireshm
const buildSortedQuery = (args) => {
return Object.keys(args)
.sort()
.map(key => {
return window.encodeURIComponent(key)
+ '='
+ window.encodeURIComponent(args[key]);
})
.join('&');
};
console.log(buildSortedQuery({
foo: "hi there",
bar: "100%"
}));
//bar=100%25&foo=hi%20there
Just use the following:
encodeURIComponent(JSON.stringify(obj))
// elastic search example
let story ={
"query": {
"bool": {
"must": [
{
"term": {
"revision.published": 0,
}
},
{
"term": {
"credits.properties.by.properties.name": "Michael Guild"
}
},
{
"nested": {
"path": "taxonomy.sections",
"query": {
"bool": {
"must": [
{
"term": {
"taxonomy.sections._id": "/science"
}
},
{
"term": {
"taxonomy.sections._website": "staging"
}
}
]
}
}
}
}
]
}
}
}
const whateva = encodeURIComponent(JSON.stringify(story))
console.log(whateva)
const querystring= {};
querystring.stringify = function (obj, sep = '&', eq = '=') {
const escape = encodeURIComponent;
const qs = [];
let key = null;
for (key in obj) if (obj.hasOwnProperty(key)) {
qs.push(escape(key) + eq + escape(String(obj[key])));
}
return qs.join(sep);
};
Example:
const a = querystring.stringify({a: 'all of them', b: true});
console.log(a); // Output: a=all%20of%20them&b=true
While there are limits to query-string lengths that should be considered (for sending JSON data in HTTP/s GET calls versus using POST)...
JSON.stringify(yourJSON) will create a String from your JSON object.
Then just hex-encode it (link below).
That will work always versus various possible problems with base64 type URL encoding, UTF-8 characters, nested JSON objects and such.
You can pass an object to this function with undefined properties. If the property exist, it will be converted to a query string and the query string will be returned.
function convertToQueryString(props) {
const objQueryString = { ...props };
for (const key in objQueryString) {
if (!key) {
delete objQueryString[key];
}
}
const params = JSON.stringify(objQueryString);
const qs = params
.replace(/[/''""{}]/g, '')
.replace(/[:]/g, '=')
.replace(/[,]/g, '&');
console.log(qs)
return qs;
}
convertToQueryString({order: undefined, limit: 5, page: 1})
let data = {
id:1,
name:'Newuser'
};
const getqueryParam = data => {
let datasize = Object.keys(data).length;
let initial = '?';
Object.keys(data).map(function (key, index) {
initial = initial.concat(`${key}=${data[key]}`);
index != datasize - 1 && (initial = initial.concat('&'));
});
console.log(initial, 'MyqueryString');
return initial;
};
console.log(getqueryParam(data))//You can get the query string here
If you have baseUrl means to get full query use
baseUrl.concat(getqueryParam(data))
For TS
const convertQueryToString = (data: { [x: string]: any }): string => {
const serialize = (obj: { [x: string]: any }, prefix?: string): string => {
const str = [];
let p;
for (p in obj) {
if (obj.hasOwnProperty(p)) {
const k = prefix ? `${prefix}[${p}]` : p;
const v = obj[p];
str.push(
v !== null && typeof v === 'object' ? serialize(v, k) : `${encodeURIComponent(k)}=${encodeURIComponent(v)}`
);
}
}
return str.join('&');
};
return serialize(data);
};
You can also achieve this by using simple JavaScript.
const stringData = '?name=Nikhil&surname=Mahirrao&age=30';
const newData= {};
stringData.replace('?', '').split('&').map((value) => {
const temp = value.split('=');
newData[temp[0]] = temp[1];
});
console.log('stringData: '+stringData);
console.log('newData: ');
console.log(newData);
const serialize = obj => Object.keys(obj).reduce((a, b) =>
a.push(encodeURIComponent(b) + "=" + encodeURIComponent(obj[b])) && a,
[]).join("&");
Call:
console.log(serialize({a:1,b:2}));
// output: 'a=1&b=2
'
With Ramda:
R.pipe(R.toPairs, R.map(R.join('=')), R.join('&'))({a: 'b', b: 'a'})