2
\$\begingroup\$

I have an API that returns JSON, where the value that I need is stored in either one of the two object properties:

data.d.GetContextWebInformation.FormDigestValue

or

data.value.GetContextWebInformation.FormDigestValue

The code that I'm using is pretty clumsy. At first, I used something like this:

if (data && data.d && data.d.GetContextWebInformation && data.d.GetContextWebInformation.FormDigestValue) {
    this.options.token = data.d.GetContextWebInformation.FormDigestValue;
} else {
// check for second one

Now I've rewritten it using try/catch, and it looks a bit cleaner, but still clumsy:

    var token; 
    try {
        // If Verbosity was odata=verbose:
        token = data.d.GetContextWebInformation.FormDigestValue;
    } catch (ex) {
        try {
            // If Verbosity was odata=nometadata or odata=minimalmetadata:
            token = data.value.GetContextWebInformation.FormDigestValue;
        } catch (ex) {
            throw 'Unable to obtain authorization token.';
        }
    } finally {
        if (token) { this.options.token = token; }
    }

What would be a better way to write the same code for a cleaner, nicer look? If that matters, I need to support IE9 so probably can't use newer language features.

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

If you're certain the token exists in either of the objects you can do:

First check for the existence of the value in data.

var value = data.d || data.value;

then access the value to get the token

var token = value && value.GetContextWebInformation.FormDigestValue;

var value = data.d || data.value;

var token = value && value.GetContextWebInformation.FormDigestValue;


if (token) {
  this.options.token = token;
}

Otherwise, you can use getIn function:

function getIn(pathArray, obj) {
  var tmp = obj;
  for (var i = 0; i < pathArray.length; i++) {
    if (tmp.hasOwnProperty(pathArray[i])) {
      tmp = tmp[pathArray[i]];
      continue;
    }
    return undefined;
  }
  return tmp;
}

var token = getIn(['d', 'GetContextWebInformation', 'FormDigestValue'], data) ||
            getIn(['value', 'GetContextWebInformation', 'FormDigestValue'], data);

if (token) {
  this.options.token = token;
}

\$\endgroup\$
1
  • \$\begingroup\$ I would not require a pathArray list, but a path String like "d.GetContextWebInformation.FormDigestValue", it would make the calling code cleaner. \$\endgroup\$
    – konijn
    Commented Aug 10, 2017 at 15:39
-1
\$\begingroup\$

You can use {} fallbacks at each nesting level.

((data && (data.d || data.value) || {}).GetContextWebInformation || {}).FormDigestValue

I'm not saying it's more readable in non-trivial cases, though.
In the bright future we might be able to use optional chaining e.g. var foo = a?.b?.c?.d

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.