76

In Ruby, is there a way to check if a string is valid json before trying to parse it?

For example getting some information from some other urls, sometimes it returns json, sometimes it could return a garbage which is not a valid response.

My code:

def get_parsed_response(response)
  parsed_response = JSON.parse(response)
end
Simone Carletti
  • 173,507
  • 49
  • 363
  • 364
Sam
  • 5,040
  • 12
  • 43
  • 95
  • 8
    I'm pretty sure parsing it is the only way to know for sure it's valid. Why not parse it and handle the parsing error telling you it's invalid? – T.J. Crowder Oct 07 '14 at 09:35
  • 3
    for example this way `JSON.parse(string) rescue nil` – gotva Oct 07 '14 at 09:36
  • 1
    Theoretically, there should be a way. Parsing a string results in a properly stronger information than knowing whether it is parsable or not. In Chomsky's term, regarding natural language, this distinction corresponds to strong versus weak generative capacity. However, what's wrong with rescuing the error as with the comments above? – sawa Oct 07 '14 at 09:53
  • 2
    Or you could use a [Regex to validate JSON](http://stackoverflow.com/questions/2583472/regex-to-validate-json) – Stefan Oct 07 '14 at 09:55
  • @gotva - Can you give me the correct rescue syntax? – Sam Oct 07 '14 at 10:09
  • above is a short syntax. If you would like to handle exception more accurate look at [this gist](https://gist.github.com/gotva/42c32c418f7a05398957) – gotva Oct 07 '14 at 10:12
  • 1
    Technically speaking, the process of determining whether a string is valid in a language *is* parsing. Building a data-structure telling you *how* it is valid is actually just a side-effect of that. – Jörg W Mittag Oct 07 '14 at 10:50
  • @JörgWMittag There are ways to determine if a string is parsable without parsing it. For example, consider a language that consists of the alphabet `a` and `b`, and whose BNF is (something like) `S := aSa|b`. You can tell whether a string confirms to this language by just seeing that there is exactly one `b`, and the numbers of `a` on both sides of it are the same. That does not mean that you have the tree. Parsing means you have the tree structure. – sawa Oct 07 '14 at 11:17

4 Answers4

88

You can create a method to do the checking:

def valid_json?(json)
  JSON.parse(json)
  true
rescue JSON::ParserError, TypeError => e
  false
end
duhaime
  • 25,611
  • 17
  • 169
  • 224
Richa Sinha
  • 1,406
  • 15
  • 29
30

You can parse it this way

begin
  JSON.parse(string)  
rescue JSON::ParserError => e  
  # do smth
end 

# or for method get_parsed_response

def get_parsed_response(response)
  parsed_response = JSON.parse(response)
rescue JSON::ParserError => e  
  # do smth
end
gotva
  • 5,919
  • 2
  • 25
  • 35
  • 2
    Please note that there may be 'TypeError' if under there would be something that cannot be implicitly converted to string(e.g. nil) – Leaf Apr 16 '15 at 14:56
14

I think parse_json should return nil if it's invalid and shouldn't error out.

def parse_json string
  JSON.parse(string) rescue nil
end

unless json = parse_json string
  parse_a_different_way
end
stevo999999
  • 588
  • 4
  • 12
  • 2
    Because its prettier... in fact, I'm considering opening up JSON and creating a method called parse_without_error. – stevo999999 Mar 13 '17 at 21:18
  • 1
    Note that `null` and `false` are valid JSON, too. `JSON.parse` returns `nil` and `false` which would be treated as a parse error in the code above. – Daniel Rikowski Oct 03 '17 at 10:35
2

Let me suggest a shorter variant

def valid_json?(string)
  !!(JSON.parse(string)) rescue false
end

> valid_json?("test")
=> false

> valid_json?("{\"mail_id\": \"999129237\", \"public_id\": \"166118134802\"}")
=> true
installero
  • 9,096
  • 3
  • 39
  • 43