ngrx-store-localstorage icon indicating copy to clipboard operation
ngrx-store-localstorage copied to clipboard

JSON.parse throwing error for invalid JSON not handled

Open vileanco opened this issue 6 years ago • 5 comments

If local storage contains invalid JSON object, for example {hello":"world"}, JSON.parse throws an error which is not handled by ngrx-store-localstorage. Should this error be handled within the library or should it be responsibility of the user of the library?

Unhandled Promise rejection: Unexpected token a in JSON at position 1 ; Zone: <root> ; Task: Promise.then ; Value: SyntaxError: Unexpected token a in JSON at position 1

Affects [email protected] with Google Chrome version 67.0.3396.99.

One way to solve this issue would be to allow user to pass custom json parsing function to the library.

vileanco avatar Aug 10 '18 08:08 vileanco

You can specify the JSON parsing function when specifying the state key in the configuration as an object passed to the localStorageSync. You must pass a serialize and deserialize function to accomplish this as follow:

localStorageSync({
    "keys": [
      {
        "greeting": {
          "serialize": myJsonSerializer,
          "deserialize": myJsonDeserializer
        }
      },
      {...},
      ...
    ]
  })

ernestomancebo avatar Aug 17 '18 13:08 ernestomancebo

I also thought so but it seems that the raw data is put through JSON.parse before deserializer is called, therefore it will still give an error even if I give it my own jsonDeserializer.

https://github.com/btroncone/ngrx-store-localstorage/blob/master/src/index.ts

starting from line 92:

const isObjectRegex = new RegExp('{|\\[');
let raw = stateSlice;

if (stateSlice === 'null' || isObjectRegex.test(stateSlice.charAt(0))) {
    raw = JSON.parse(stateSlice, reviver);
}

return Object.assign({}, acc, {
     [key]: deserialize ? deserialize(raw) : raw
 });

vileanco avatar Aug 17 '18 14:08 vileanco

I got your point, but if you see closer to the lines 127, then the 183, you can see that first serialize then stringify and then when retrieving the state, should do the inverse and it's what you point out: parse then deserialize. Somehow the string-stored state is being corrupted or you're generating a string by yourself from an object (then passing the condition in line 181), which is why is not a parseable JSON.

https://github.com/btroncone/ngrx-store-localstorage/blob/c3954e29a006e185402d22f2e5a5439bf19c504b/src/index.ts#L127

https://github.com/btroncone/ngrx-store-localstorage/blob/c3954e29a006e185402d22f2e5a5439bf19c504b/src/index.ts#L183

https://github.com/btroncone/ngrx-store-localstorage/blob/c3954e29a006e185402d22f2e5a5439bf19c504b/src/index.ts#L181

ernestomancebo avatar Aug 17 '18 14:08 ernestomancebo

Yes, the string in local storage was corrupted by a user (using browser dev tools) which then caused JSON.parse to throw error and the whole application not to work.

So if I want to store my data as JSON string in local storage, there is no way to avoid this issue. This is because of condition isObjectRegex.test(stateSlice.charAt(0)) so no matter if I pass deserializer or not, JSON.parse will be called and it will fail. It seems that the library trusts that the data coming from outside is actually valid json, which is a problem in itself. Unless I am missing something...

vileanco avatar Aug 17 '18 16:08 vileanco

any toughs @btroncone ?

ernestomancebo avatar Aug 17 '18 18:08 ernestomancebo