napolux
napolux

Reputation: 16074

Query-string encoding of a JavaScript object

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 :)

Upvotes: 738

Views: 669516

Answers (30)

Alex Escalante
Alex Escalante

Reputation: 467

Here is a one-liner:

const encoded = Object.entries(obj).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join("&");

Upvotes: 23

Pavlo Sadovyi
Pavlo Sadovyi

Reputation: 79

In ES7, you can write this in one line:

const serialize = (obj) => (Object.entries(obj).map(i => [i[0], encodeURIComponent(i[1])].join('=')).join('&'))

Upvotes: 4

Leandro Santiago Gomes
Leandro Santiago Gomes

Reputation: 147

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

Upvotes: 5

Long Ranger
Long Ranger

Reputation: 6008

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

Upvotes: 0

jssebastian
jssebastian

Reputation: 1189

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.

Upvotes: 26

Valentyn Domanskyi
Valentyn Domanskyi

Reputation: 1

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

Upvotes: -1

Tim Down
Tim Down

Reputation: 324567

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() );

Upvotes: 12

benvds
benvds

Reputation: 3726

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.

Upvotes: 253

alf
alf

Reputation: 18530

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("&")

Upvotes: 7

sergk
sergk

Reputation: 3631

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

Upvotes: 139

A.Aziem Moemen
A.Aziem Moemen

Reputation: 41

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.

Upvotes: 4

With Node.js v6.6.3

const querystring = require('querystring')

const obj = {
  foo: 'bar',
  baz: 'tor'
}

let result = querystring.stringify(obj)
// foo=bar&baz=tor

Reference: Query string

Upvotes: 70

Vandana Sharma
Vandana Sharma

Reputation: 21

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

Upvotes: 2

Sheharyar
Sheharyar

Reputation: 75750

Ruby on Rails and PHP style query builder

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

Upvotes: 32

Laravel Plus
Laravel Plus

Reputation: 49

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

Upvotes: 4

gandharv garg
gandharv garg

Reputation: 2171

ES6 solution for query string encoding of a JavaScript object

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"

Upvotes: 4

itay oded
itay oded

Reputation: 1040

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

Upvotes: 0

AntonAL
AntonAL

Reputation: 17410

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

Upvotes: 0

Δ O
Δ O

Reputation: 3710

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

Upvotes: 2

Sergey Onishchenko
Sergey Onishchenko

Reputation: 7851

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"}

Upvotes: 0

Darrell Teague
Darrell Teague

Reputation: 4282

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.

References

JSON.stringify()

Encode String to HEX

Upvotes: -1

Skriptas
Skriptas

Reputation: 889

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

Upvotes: 6

dipenparmar12
dipenparmar12

Reputation: 3455

To do it in a better way.

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.

Logic, Functionality

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

Example

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

Live Test

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

Things to consider.

  • It skips values for functions, null, and undefined
  • It skips keys and values for empty objects and arrays.
  • It doesn't handle Number or String objects made with new Number(1) or new String('my string') because no one should ever do that

Upvotes: 3

Bhairesh M
Bhairesh M

Reputation: 145

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

Upvotes: 1

Soldeplata Saketos
Soldeplata Saketos

Reputation: 3461

TypeScript version for PHP notation (no URL escaped version)

/**
 * 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("&");
};

Upvotes: 1

Bhuvnesh
Bhuvnesh

Reputation: 280

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

Or use a predefined feature

const data = {
  offset: 5,
  limit: 10
};

new URLSearchParams(data).toString(); // => ?offset=5&limit=10

Note

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.

Upvotes: 7

Erich Stark
Erich Stark

Reputation: 41

URLSearchParams looks good, but it didn't work for nested objects.

Try to use

encodeURIComponent(JSON.stringify(object))

Upvotes: 1

matheus miranda
matheus miranda

Reputation: 1

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

Upvotes: -1

user187291
user187291

Reputation: 53940

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

Upvotes: 982

Priyashanmgugaraj
Priyashanmgugaraj

Reputation: 9

 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))

Upvotes: -1

Related Questions