1

Say we have a function that calls JSON.parse(someText) multiple times. However, someText is not necessarily error checked, for ex, "foo" could be passed into JSON.parse. When a non JSON value is inputted, I want to return an empty object, {}

Obviously, we can use a try-catch to easily handle this. However, try-catch is ugly and not elegant - is there a quick, simple, one liner way to do something like this?

erli
  • 358
  • 4
  • 16
  • 4
    If you put the try/catch in a function, calling the function becomes a quick, simple one-liner. It also helps if you decide you want more validation (e.g. `null` not allowed even though it parses, or no root types other than object at all). – Ry- Jul 12 '19 at 23:37
  • 1
    @Ry- It was meant for your comment as well as to agree with the statement in the question's second paragraph – Pieter Jul 12 '19 at 23:41
  • 1
    @Pieter: Not sure what it has to do with my comment either. `try` is how you handle JSON parsing errors in JavaScript. There’s no option to make it not throw, which is why it’s necessary to create one the way I just described. – Ry- Jul 12 '19 at 23:42
  • @Ry- I must be misunderstanding your comment "If you put the try/catch in a function, calling the function becomes a quick, simple one-liner." A try/catch won't catch `foo` or `someText` as specified a requirement in the question – Pieter Jul 12 '19 at 23:44
  • 3
    @Pieter: `const parseOrDefault = (json, def) => { try { return JSON.parse(json); } catch (err) { return def; } };` – Ry- Jul 12 '19 at 23:45
  • @Ry- I don't understand how that code will only parse valid JSON and not plain text or null. Also, if you don't sanitise the json string then you are relying on the try/catch to "clean up" for you as oppose to it being an _exception_ to what's expected – Pieter Jul 12 '19 at 23:47
  • 1
    @Pieter: How do you sanitize a JSON string? (Bonus points for answers that are *not* more fragile than catching the exception.) Seriously, this is how you do it in JavaScript. The function wrapper can certainly be improved by checking that `json` is a string, and maybe even checking the type of `err` (because it can be a stack overflow), but the `try` is constant. – Ry- Jul 12 '19 at 23:49
  • 1
    @Ry- I will take your word for that then as I come from a C# backend and avoid try/catch unless it's something truly unexpected and will accept that in JS it might work different. Also, I completely missed the second sentence in your first comment which it what I couldn't understand in your code, but you explained it in there. Apologies. – Pieter Jul 13 '19 at 00:03
  • @Pieter `I come from a C# backend` A lot of coders in JS have different backgrounds, I came from C,C++ & C#, Delphi, and lots of others I dare not mention. But yes, overuse capturing exceptions is always best avoided, but an invalid JSON is indeed an unexpected exception, that try / catch was designed for. So for this particular problem is the ideal solution. – Keith Jul 13 '19 at 00:07
  • There is a full insight into what you are looking for here (https://stackoverflow.com/questions/3710204/how-to-check-if-a-string-is-a-valid-json-string-in-javascript-without-using-try/3710294#comment63309174_3710506) – Udo E. Jul 13 '19 at 00:10

2 Answers2

0

(this goes to future readers that don't get why this is wrong) You are supposed to catch and handle exceptions, not ignore them. People that develop these functions rely on you catching exceptions to be able to properly react to them breaking. Elegance and beauty are in the eyes of the beholder, and as with any piece of art, you write it so that other people will enjoy it. And everyone gets try...catch blocks.

There's no way to do it in 1 line of code. You can however, do some nasty stuff to bypass exception handling.


METHOD 1

Manually handle the global onError method.

function handleErr(msg, url, line_no){ 
   var errorMsg = "Error: " + msg + "\n"; 
       errorMsg += "URL: " + url + "\n"; 
       errorMsg += "Line: " + line_no + "\n\n"; 

    console.log(errorMsg); 

 return true;
} 

// Set the global onerror; 
onerror = handleErr;

Now you handle (i.e. ignore) errors in this function. You can switch it on and off with a bit code. Or you can go bananas and just do a return true; in the handler.


METHOD 2

Use setTimeout, the thread will die due to the exception but your code will keep executing, also a beautiful ES6 one-liner.

setTimeout(() => JSON.parse("not json: fghfghg"), 0)
console.log("Code still running")

METHOD 3

For non-mainstream, "Elegant" exception handling you can implement and use Either (example)

DanyAlejandro
  • 1,440
  • 13
  • 24
  • 1
    These don’t really satisfy the “when a non JSON value is inputted, I want to return an empty object” part. – Ry- Jul 13 '19 at 00:12
  • @Ry- JSON.parse will always throw an exception if an invalid string is encountered. Ignoring that exception will just over labour your code – Udo E. Jul 13 '19 at 00:16
  • @UdoE.: Is that supposed to be a comment on this answer and not to me? – Ry- Jul 13 '19 at 00:20
  • the comment is for future beginners looking for a way to "solve" exceptions. And yeah, returning an empty object will require a wrapper to run these things, so I guess this doesn't answer the question. – DanyAlejandro Jul 13 '19 at 02:17
  • @Ry- it reinforces the point the first paragraph on this answer is making. – Udo E. Jul 13 '19 at 04:21
0

Despite previous comments about exception handling, you can apply a one-liner to achieve your goal. The only catch is numbers and numeric strings; those will be parsed and returned as numbers

let input = 'someText'
let parsedText = (() => { try { return JSON.parse(input) } catch { return {} }}).call()
console.info(parsedText) // {}

input = '{ "hello": "world" }'
parsedText = (() => { try { return JSON.parse(input) } catch { return {} }}).call()
console.info(parsedText) // { hello: 'world' }

input = '9'
parsedText = (() => { try { return JSON.parse(input) } catch { return {} }}).call()
console.info(parsedText) // 9