How can I simplify access to the values of interest of a JSON in Javascript?

Asked

Viewed 104 times

2

Context: I’m developing an application that consumes multiple Apis. The JSON returned by these Apis have their own structure, where it is often not the most intuitive for the programmer to explore them.

Example: suppose I am using an external API, and that this is JSON returned from any route.

{
  "arvore": {
    "avo": {
      "pai": {
        "eu": "pedro"
      }
    }
  }
}

Suppose also that the only information that interests me in that JSON is the key value eu. This way, every time I consume this resource and get this JSON, I will have to access my information of interest so: obj['arvore']['avo']['pai']['eu'] or so obj.arvore.avo.pai.eu, etc..

Problem/nuisance: access to this information of interest is very verbose. And this can inhibit a little the speed of the development process in a larger scenario, finally.


I was thinking of creating a kind of wrapper for the returned JSON - of the resources I most consume-. For example, instead of accessing the key through its actual structure (obj['arvore']['avo']['pai']['eu']), I could just give a obj.eu and then would have exactly the same result. However, before implementing this, I wanted to raise this discussion here. In addition, I thank you.

  • Mixin with an object of yours that has quick access methods. Mixin is the key word.

  • 2

    It lacked the language of context. Although the format of your explanation is like python, is that it? If it is enough a class that reads the json and makes available what you want, in the desired format, although I would not waste time with it, if it were not the main goal.

  • As Mr @Sidon said, it would be good to clarify the language in question (whether it is JS or what). I believe that [Edit] the question to put the desired language tag is enough. I would add that being verbose should probably not be a problem, since any good editor has copy&paste and search/replace if he needs to make a change. Depending on the language, a #define would be enough to simplify typing or centralize the path in a specific place. Could still create some variable by reference, something like eu = &obj['arvore']['avo']['pai']['eu']

  • Actually I needed this in Python and Javascript. However, to be more organized, I will direct this question to Javascript.

3 answers

0

It’s a bit far-fetched, but you can do a recursive function that looks for the object’s Ntries and if the first return key is equal to the key you’re looking for, then return that value - otherwise call the function again with the according to return value:

const tree = {
  "arvore": {
    "avo": {
      "pai": {
        "eu": {
          "nome": "pedro",
          "familia": "dev"
        }
      }
    }
  }
}

function getObjectValueByKey(key, _pool) {
  const pool = Object.entries(_pool);
  let found = null;

  pool[0].forEach(entry => {
    if (entry === key) {
      found = pool[0][1];
    }
  });

  if (found) return found;
  else return getObjectValueByKey(key, pool[0][1]);
}


const value = getObjectValueByKey('eu', tree);
console.log('value?', value);

0


I found a simple solution using methods static of Ecmascript 6, as follows in the code. In them, I define as return the path to my information of interest, simple as this.

    var obj = {
        "arvore": {
            "avo": {
                "pai": {
                    "eu": "pedro"
                }
            }
        }
    }

    class Access {
        static getEu(obj) {
            return obj.arvore.avo.pai.eu;
        }
    }

    document.body.innerHTML = Access.getEu(obj);

  • I wouldn’t recommend using a class this way just to put a static method in it, it doesn’t make much sense, if so, using a function was simpler.

  • So I used the classes more to create groups. Because in a real context, with dozens of functions, classes (or groups) would help a little.

  • If you are using ES6, Imports/Exports already solve this problem...

0

You can create a function that creates an alias for your object, always pointing to the path defined by the function.

function get(source, path) {
  return path.split('.').reduce((currentValue, propertyName) => {
    return currentValue && currentValue[propertyName]
  }, source);
}

function alias(source, aliasName, path) {
  return Object.defineProperty(source, aliasName, {
    get() {
      return get(this, path);
    }
  });
}

const obj = {
  "arvore": {
    "avo": {
      "pai": {
        "eu": "pedro"
      }
    }
  }
};

const decorated = alias(obj, 'eu', 'arvore.avo.pai.eu');

decorated.eu; // "pedro"

decorated.arvore.avo.pai.eu = "joão";

decorated.eu; // "joão"

If you want multiple aliases:

function aliases(source, aliases) {
  return aliases.reduce((decorated, args) => {
    return alias(decorated, ...args)
  }, source);
}

const decorated = aliases(obj, [
  ['avo', 'arvore.avo'],
  ['pai', 'avo.pai'],
  ['eu', 'pai.eu']
]);

Browser other questions tagged

You are not signed in. Login or sign up in order to post.