What's the difference between JSON.load and JSON.parse methods of Ruby lib?
JSON#parse
parses a JSON string into a Ruby Hash.
JSON.parse('{"name": "Some Name"}') # => {"name" => "Some Name"}
JSON#load
takes either a string or IO (file etc) and converts that to Ruby Hash/Array
JSON.load File.new("names.json") # => Reads the JSON inside the file and results in a Ruby Object.
JSON.load '{"name": "Some Name"}' # Works just like #parse
In fact, it converts any object that responds to a #read
method. For example:
class A
def initialize
@a = '{"name": "Some Name"}'
end
def read
@a
end
end
JSON.load(A.new) # => {"name" => "Some Name"}
A key difference is that JSON.load
is unsafe when given untrusted input (the same can be achieved with JSON.parse
, but it has safe defaults). This is because it provides a way to instantiate classes other than the "normal" Hash, String, Array, Number classes:
class Foo
def self.json_creatable?
true
end
def self.json_create attributes
puts "called with #{attributes}"
end
end
JSON.parse('{"json_class": "Foo"}') #=> {"json_class"=>"Foo"}
whereas
JSON.load('{"json_class": "Foo"}')
called with {"json_class"=>"Foo"}
#=> nil
This intended for you to implement custom serialization of data - it shouldn't be used when parsing data from the wide world. Of course you do need to implement the json_creatable?
and json_create
methods for this to actually achieve anything, but how confident are you that none of your dependencies do this or implement method_missing
in such a way that it could be misused ? (see for example the Marshal.load
exploits. As a result of this JSON.load
& JSON.parse
were tightened up significantly).
Always use JSON.parse
when dealing with untrusted data or unless you need the extra capabilities of JSON.load
One more difference is that JSON.load
parses single value (not object and not array) by default.
JSON.load("false")
=> false
JSON.load("123")
=> 123
But JSON.parse
requires quirks mode
to be enabled to parse such value.
JSON.parse("false")
JSON::ParserError: 757: unexpected token at 'false'
JSON.parse("false", quirks_mode: true)
=> false