68

I got a JavaScript object which I would like to get x-www-form-urlencoded.

Something like $('#myform').serialize() but for objects.

The following object:

{
    firstName: "Jonas",
    lastName: "Gauffin"
}

would get encoded to:

firstName=Jonas&lastName=Gauffin (do note that special characters should get encoded properly)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • Asked before: http://stackoverflow.com/questions/3848340/is-there-a-better-way-to-convert-a-json-packet-into-a-query-string – Frank van Wijk Mar 28 '12 at 14:30
  • Please provide an example input and output. If you want simply want to encode JSON, [`encodeURIComponent(json)`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/encodeURIComponent) should be fine. – Felix Kling Mar 28 '12 at 14:44

12 Answers12

75

I'm surprised that no one has mentioned URLSearchParams

var prms = new URLSearchParams({
  firstName: "Jonas",
  lastName: "Gauffin"
});
console.log(prms.toString());
// firstName=Jonas&lastName=Gauffin
tipster
  • 766
  • 6
  • 2
  • 3
    Should definitely be the accepted answer. Just know that it doesn't work in IE yet. Check CanIUse to find out if that's changed: https://caniuse.com/#search=URLSearchParams – Eric Seastrand May 02 '19 at 18:01
  • Let's face it our grannies that still use IE would never encounter such sophisticated apps – Moe Dec 22 '21 at 20:43
66

Please look closely at both answers I provide here to determine which fits you best.


Answer 1:

Likely what you need: Readies a JSON to be used in a URL as a single argument, for later decoding.

jsfiddle

encodeURIComponent(JSON.stringify({"test1":"val1","test2":"val2"}))+"<div>");

Result:

%7B%22test%22%3A%22val1%22%2C%22test2%22%3A%22val2%22%7D

For those who just want a function to do it:

function jsonToURI(json){ return encodeURIComponent(JSON.stringify(json)); }

function uriToJSON(urijson){ return JSON.parse(decodeURIComponent(urijson)); }

Answer 2:

Uses a JSON as a source of key value pairs for x-www-form-urlencoded output.

jsfiddle

// This should probably only be used if all JSON elements are strings
function xwwwfurlenc(srcjson){
    if(typeof srcjson !== "object")
      if(typeof console !== "undefined"){
        console.log("\"srcjson\" is not a JSON object");
        return null;
      }
    u = encodeURIComponent;
    var urljson = "";
    var keys = Object.keys(srcjson);
    for(var i=0; i <keys.length; i++){
        urljson += u(keys[i]) + "=" + u(srcjson[keys[i]]);
        if(i < (keys.length-1))urljson+="&";
    }
    return urljson;
}

// Will only decode as strings
// Without embedding extra information, there is no clean way to
// know what type of variable it was.
function dexwwwfurlenc(urljson){
    var dstjson = {};
    var ret;
    var reg = /(?:^|&)(\w+)=(\w+)/g;
    while((ret = reg.exec(urljson)) !== null){
        dstjson[ret[1]] = ret[2];
    }
    return dstjson;
}
johnny 5
  • 19,893
  • 50
  • 121
  • 195
Grallen
  • 1,620
  • 1
  • 17
  • 16
22

Since you were asking for a serialized object, this is probably slightly off the mark. But just in case, if your intent is to use the values within that object as individual parameters, this might be the conversion you're looking for:

var params = {
    "param1": "arg1",
    "param2": "arg2"
};
var query = "";
for (key in params) {
    query += encodeURIComponent(key)+"="+encodeURIComponent(params[key])+"&";
}
xmlhttp.send(query);
kmuenkel
  • 2,659
  • 1
  • 19
  • 20
  • Good in theory, only issue is that there will always be a trailing "&" at the end. I used a very similar method, but instead I set array values, and then used `join("&")`. Works well. – SuperJumpBros Aug 19 '21 at 05:32
22

See jQuery.param(...). Converts to uri, see link for more information!

jb10210
  • 1,158
  • 5
  • 15
4

Same as above in effect, but functional style gives an elegant expression::

const to_encoded = obj => Object.keys(obj).map(k =>
    `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`).join('&');
BaseZen
  • 8,650
  • 3
  • 35
  • 47
  • `const toEncoded = (obj: { [key: string]: string }) =>`... keeps typescript happy – ryanrain Jul 24 '19 at 06:08
  • Wondering why you can't simply pass the whole joined string to encodeURIComponent(...join('&')) ??? The MDN docs would have you believe you can... https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent – mattdlockyer Oct 31 '19 at 21:57
3

FYI, the accepted answer doesn't include support for nested objects. Here's one way that you can accomplish this:

function xwwwfurlenc(srcjson, parent=""){
    if(typeof srcjson !== "object")
      if(typeof console !== "undefined"){
        console.log("\"srcjson\" is not a JSON object");
        return null;
    }

    let u = encodeURIComponent;
    let urljson = "";
    let keys = Object.keys(srcjson);

    for(let i=0; i < keys.length; i++){
      let k = parent ? parent + "[" + keys[i] + "]" : keys[i];

      if(typeof srcjson[keys[i]] !== "object"){
        urljson += u(k) + "=" + u(srcjson[keys[i]]);
      } else {
        urljson += xwwwfurlenc(srcjson[keys[i]], k)
      }
      if(i < (keys.length-1))urljson+="&";
    }

    return urljson;
}
Curt
  • 149
  • 1
  • 4
3

An extension to @Grallen's Answer 1 – if you need a shorter URL:

Input:

{"q":"SomethingTM","filters":[{"kind":"A","q":"foobar"},{"kind":"B","isntIt":true}],"pagenumber":1}

Output:

('q'~'SomethingTM'_'filters'~!('kind'~'A'_'q'~'foobar')_('kind'~'B'_'isntIt'~true)*_'pagenumber'~1)

Instead of:

%7B%22q%22%3A%22SomethingTM%22%2C%22filters%22%3A%5B%7B%22kind%22%3A%22A%22%2C%22q%22%3A%22foobar%22%7D%2C%7B%22kind%22%3A%22B%22%2C%22isntIt%22%3Atrue%7D%5D%2C%22pagenumber%22%3A1%7D

function jsonToUri(v, r, s) {
  return encodeURIComponent(
    JSON.stringify(v, r, s)
    .replace(/[()'~_!*]/g, function(c) {
      // Replace ()'~_!* with \u0000 escape sequences
      return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4)
    })
    .replace(/\{/g, '(')    //    { -> (
    .replace(/\}/g, ')')    //    } -> )
    .replace(/"/g,  "'")    //    " -> '
    .replace(/\:/g, '~')    //    : -> ~
    .replace(/,/g,  '_')    //    , -> _
    .replace(/\[/g, '!')    //    [ -> !
    .replace(/\]/g, '*')    //    ] -> *
  )
}

function uriToJson(t, r) {
  return JSON.parse(
    decodeURIComponent(t)
    .replace(/\(/g, '{')    //    ( -> {
    .replace(/\)/g, '}')    //    ) -> }
    .replace(/'/g,  '"')    //    ' -> "
    .replace(/~/g,  ':')    //    ~ -> :
    .replace(/_/g,  ',')    //    _ -> ,
    .replace(/\!/g, '[')    //    ! -> [
    .replace(/\*/g, ']')    //    * -> ]
    , r
  )
}



//////// TESTS ////////



var a = {q: 'SomethingTM', filters: [{kind: 'A', q: 'foobar'}, {kind: 'B', isntIt: true}], pagenumber: 1}
var b = jsonToUri(a)
var c = uriToJson(b)

console.log(b)
// ('q'~'SomethingTM'_'filters'~!('kind'~'A'_'q'~'foobar')_('kind'~'B'_'isntIt'~true)*_'pagenumber'~1)

console.log(JSON.stringify(c))
// {"q":"SomethingTM","filters":[{"kind":"A","q":"foobar"},{"kind":"B","isntIt":true}],"pagenumber":1}

var a2 = {"q":"Something(TM)","filters":[{"kind":"A*","q":"foo_bar"},{"kind":"B!","isn'tIt":true}],"page~number":1}
var b2 = jsonToUri(a2)
var c2 = uriToJson(b2)

console.log(b2)
// ('q'~'Something%5Cu0028TM%5Cu0029'_'filters'~!('kind'~'A%5Cu002a'_'q'~'foo%5Cu005fbar')_('kind'~'B%5Cu0021'_'isn%5Cu0027tIt'~true)*_'page%5Cu007enumber'~1)

console.log(JSON.stringify(c2))
// {"q":"Something(TM)","filters":[{"kind":"A*","q":"foo_bar"},{"kind":"B!","isn'tIt":true}],"page~number":1}
andraaspar
  • 796
  • 6
  • 10
2

To build on @Claymore's answer, Here is a function to encode an object and additionally omit the trailing ampersand:

encodeObject(params) {
  var query = [];
  for (let key in params) {
    let val = encodeURIComponent(key) + "=" + encodeURIComponent(params[key]);
    query.push(val);
  }
  return query.join('&');
}
johnny 5
  • 19,893
  • 50
  • 121
  • 195
1
function jsonToURI(jsonObj) {
    var output = '';
    var keys = Object.keys(jsonObj);
    keys.forEach(function(key) {
        output = output + key + '=' + jsonObj[key] + '&';
    })
    return output.slice(0, -1);
}

function uriToJSON(urijson) {
    var output = {};
    urijson = decodeURIComponent(urijson);
    urijson = urijson.split('&');
    urijson.forEach(function(param) {
        var param = param.split('=');
        output[param[0]] = param[1];
    })
    return output
}
Nadhas
  • 5,421
  • 2
  • 28
  • 42
0

let urlParameters = Object.entries(data).map(e => e.join('=')).join('&');

Try using this.

Vaibhav C
  • 19
  • 5
0

create a function to parse the query params.

const parseQueryParams = (query) => {
  return Object.entries(query)
    .map(([key, value]) => key + '=' + encodeURIComponent(value))
    .join('&')
}
snitz
  • 1
-5

You need to use JSON.stringify() to serialize the JSON/JavaScript object.

It is natively available in almost all the modern browsers but you can include the below js which will add the required library incase it is not available.

http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js

ShankarSangoli
  • 69,612
  • 13
  • 93
  • 124