8

I have a Ruby on Rails JSON question.

I have what I think is a strange error. I have the following JSON string which I get like this from an external API

test = "[{'domain': 'abc.com'}, {'domain': 'def.com'}, {'domain': 'ghi.com'}]"

Now, I want to convert this string to a hash using:

hash = JSON.parse test

The problem is that it errors with:

JSON::ParserError: 419: unexpected token at '{'domain': 'abc.com'}, {'domain': 'def.com'}, {'domain': 'ghi.com'}]'

The problem now with just replacing ' with " is dangerous if any strings includes ' or ". Anyone have a solution?

sawa
  • 165,429
  • 45
  • 277
  • 381
JayC
  • 135
  • 1
  • 2
  • 11
  • You could do `JSON.parse test.gsub("'", '"')`. This will remove all the single quotes, and then parse the string – Santhosh Jan 12 '16 at 05:39
  • I get this JSON from an external API so your solution is probably the best way. Thanks! – JayC Jan 12 '16 at 05:47
  • However, there might be a problem if there is a `'` or '"' in the json values, replacing all `'` to `"` can break the json.... anyone have a solution? – JayC Jan 12 '16 at 05:50

4 Answers4

12

It's most likely because this isn't valid JSON. Change your single quotes to double quotes, like so:

test = '[{"domain": "abc.com"}, {"domain": "def.com"}, {"domain": "ghi.com"}]'

An explanation can be found here, and you can validate your JSON here.

Community
  • 1
  • 1
MyCah
  • 408
  • 3
  • 8
  • The problem is that I am getting it like this from an external API. Is there a safe way to "convert" it to real JSON? Just replacing the `'`is dangerous. – JayC Jan 12 '16 at 06:09
  • You're correct about "just replacing the `'`" being dangerous. There isn't a great way to do it, unfortunately. I strongly suggest emailing the API provider (or filing an issue if they have some such system set up) and telling them that their API is incompatible with all strict JSON parsers (which is likely to include Ruby, Java, Python, PHP, .NET—just about everything except calling `eval` in a JavaScript runtime, a risk no sane developer will want to take). – Jordan Running Jan 12 '16 at 07:01
  • I solved it (ugly fix which should be pretty safe) with `JSON.parse test.gsub("{'", '{"').gsub("':'", '":"').gsub("' : '", '":"').gsub("' :'", '":"').gsub("': '", '":"').gsub("'}", '"}').gsub("':", '":').gsub(", '", ',"').gsub(",'", ',"').gsub("' ,", '",').gsub("',", '",').gsub("u'", '"').gsub("']", '"]').gsub("['", '["')` – JayC Jan 12 '16 at 21:04
  • 1
    That is ugly, and honestly shouldn't be used as a production solution. I agree with Jordan: speak to whoever provides the API. It's their responsibility to create something their users can consume (which it currently is not doing). Is this a commercial API? – MyCah Jan 13 '16 at 07:04
5

You're getting an error because your string isn't valid JSON. In JSON all property names must be double-quoted and string values must also be double-quotes. Single-quotes are never valid.

test = '[{"domain": "abc.com"}, {"domain": "def.com"}, {"domain": "ghi.com"}]'
JSON.parse(test)
# => [ { "domain" => "abc.com" },
#      { "domain" => "def.com" },
#      { "domain" => "ghi.com" } ]
Jordan Running
  • 102,619
  • 17
  • 182
  • 182
4

Using Rails 4 or above, If you want to have symbol keys instead of string keys, you can use deep_symbolize_keys method

hash = JSON.parse(test).deep_symbolize_keys

That's in addition that the real problem was invalid json as MyCah mentioned.

Peter T.
  • 8,757
  • 3
  • 34
  • 32
0

Use this piece of code. you are missing ActiveSupport::JSON

  ActiveSupport::JSON.decode json_string
wasipeer
  • 1,015
  • 11
  • 23