Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Javascript: recursively encode and decode querystring. (object to querystring, querystring to object)

I want to encode a complex json/javascript object into the standard querystring encoding.
And i want to decode this querystring back to an json/javascript object.
It should be recursively, with arrays, objects, strings, booleans and numbers.

I thought this should be easy, but was proven wrong. Does anyone have an idea, how to solve this problem?
Either in Javascript or preferably in Typescript.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

i created a gist for to recursively encode and decode querystrings (encode = object to querystring, decode = querystring to object).

Feel free to copy/paste this in your own projects.

function encode(object) {
    function reducer(obj, parentPrefix = null) {
        return function (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 (typeof val === 'boolean') {
                prev.push(`${prefix}=${val.toString().toUpperCase()}`);
                return prev;
            }

            if (['number', '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(object).reduce(reducer(object), []).join('&');
}

function decode(querystring) {
    function parseValue(value) {
        if (value === 'TRUE') return true;
        if (value === 'FALSE') return false;
        return isNaN(Number(value)) ? value : Number(value);
    }

    function dec(list, isArray = false): object {
        let obj = isArray ? [] : {};

        let recs = list.filter((item) => {
            if (item.keys.length > 1) return true;
            obj[item.keys[0]] = parseValue(item.value);
        });

        let attrs = {};
        recs.map((item) => {
            item.key = item.keys.shift();
            attrs[item.key] = [];
            return item;
        }).forEach((item) => attrs[item.key].push(item));

        Object.keys(attrs).forEach((attr) => {
            let nextKey = attrs[attr][0].keys[0];
            obj[attr] = dec(attrs[attr], typeof nextKey === 'number');
        });

        return obj;
    }

    return dec(
        querystring
            .split('&')
            .map((item) => item.split('=').map((x) => decodeURIComponent(x)))
            .map((item) => {
                return {
                    keys: item[0]
                        .split(/[\[\]]/g)
                        .filter((n) => n)
                        .map((key) => (isNaN(Number(key)) ? key : Number(key))),
                    value: item[1],
                };
            })
    );
}

let obj = {
    name: 'John Doe',
    age: 20,
    dead: false,
    children: [
        { name: 'Foo Doe' },
        { name: 'Bar Doe', frieds: ['Dan', 'Mike', { name: 'David' }] },
    ],
    pc: {
        setup: {
            motherboard: {
                features: ['FT1', 'FT2']
            }
        }
    },
};

let encoded = encode(obj);
let decoded = decode(encoded);
console.log(decoded);
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading