The JSON module allows parsing and generating JSON documents.
The general type-safe interface for parsing JSON is to invoke T.from_json on a target type T and pass either a String or IO as an argument.
require "json"
json_text = %([1, 2, 3])
Array(Int32).from_json(json_text) # => [1, 2, 3]
json_text = %({"x": 1, "y": 2})
Hash(String, Int32).from_json(json_text) # => {"x" => 1, "y" => 2} Serializing is achieved by invoking to_json, which returns a String, or to_json(io : IO), which will stream the JSON to an IO.
require "json"
[1, 2, 3].to_json # => "[1,2,3]"
{"x" => 1, "y" => 2}.to_json # => "{\"x\":1,\"y\":2}" Most types in the standard library implement these methods. For user-defined types you can define a self.new(pull : JSON::PullParser) for parsing and to_json(builder : JSON::Builder) for serializing. The following sections show convenient ways to do this using JSON::Serializable.
NOTE JSON object keys are always strings but they can still be parsed and deserialized to other types. To deserialize, define a T.from_json_object_key?(key : String) : T? method, which can return nil if the string can't be parsed into that type. To serialize, define a to_json_object_key : String method can be serialized that way. All integer and float types in the standard library can be deserialized that way.
require "json"
json_text = %({"1": 2, "3": 4})
Hash(Int32, Int32).from_json(json_text) # => {1 => 2, 3 => 4}
{1.5 => 2}.to_json # => "{\"1.5\":2}" JSON.parse
JSON.parse will return an Any, which is a convenient wrapper around all possible JSON types, making it easy to traverse a complex JSON structure but requires some casts from time to time, mostly via some method invocations.
require "json"
value = JSON.parse("[1, 2, 3]") # : JSON::Any
value[0] # => 1
typeof(value[0]) # => JSON::Any
value[0].as_i # => 1
typeof(value[0].as_i) # => Int32
value[0] + 1 # Error, because value[0] is JSON::Any
value[0].as_i + 10 # => 11 JSON.parse can read from an IO directly (such as a file) which saves allocating a string:
require "json"
json = File.open("path/to/file.json") do |file|
JSON.parse(file)
end Parsing with JSON.parse is useful for dealing with a dynamic JSON structure.
JSON.build
Use JSON.build, which uses JSON::Builder, to generate JSON by emitting scalars, arrays and objects:
require "json"
string = JSON.build do |json|
json.object do
json.field "name", "foo"
json.field "values" do
json.array do
json.number 1
json.number 2
json.number 3
end
end
end
end
string # => %<{"name":"foo","values":[1,2,3]}> to_json
to_json, to_json(IO) and to_json(JSON::Builder) methods are provided for primitive types, but you need to define to_json(JSON::Builder) for custom objects, either manually or using JSON::Serializable.
Writes JSON into the given IO.
Returns the resulting String of writing JSON to the yielded JSON::Builder.
Parses a JSON document as a JSON::Any.
The JSON.mapping macro defines how an object is mapped to JSON.
DEPRECATED use JSON::Serializable instead (the legacy behaviour is also available in a shard at github:crystal-lang/json_mapping.cr)
This is a convenience method to allow invoking JSON.mapping with named arguments instead of with a hash/named-tuple literal.
DEPRECATED use JSON::Serializable instead (the legacy behaviour is also available in a shard at github:crystal-lang/json_mapping.cr)
Writes JSON into the given IO. A JSON::Builder is yielded to the block.
Returns the resulting String of writing JSON to the yielded JSON::Builder.
require "json"
string = JSON.build do |json|
json.object do
json.field "name", "foo"
json.field "values" do
json.array do
json.number 1
json.number 2
json.number 3
end
end
end
end
string # => %<{"name":"foo","values":[1,2,3]}> The JSON.mapping macro defines how an object is mapped to JSON.
require "json"
class Location
JSON.mapping(
lat: Float64,
lng: Float64,
)
end
class House
JSON.mapping(
address: String,
location: {type: Location, nilable: true},
)
end
house = House.from_json(%({"address": "Crystal Road 1234", "location": {"lat": 12.3, "lng": 34.5}}))
house.address # => "Crystal Road 1234"
house.location # => #<Location:0x10cd93d80 @lat=12.3, @lng=34.5>
house.to_json # => %({"address":"Crystal Road 1234","location":{"lat":12.3,"lng":34.5}})
houses = Array(House).from_json(%([{"address": "Crystal Road 1234", "location": {"lat": 12.3, "lng": 34.5}}]))
houses.size # => 1
houses.to_json # => %([{"address":"Crystal Road 1234","location":{"lat":12.3,"lng":34.5}}]) JSON.mapping must receive a series of named arguments, or a named tuple literal, or a hash literal, whose keys will define Crystal properties.
The value of each key can be a type. Primitive types (numbers, string, boolean and nil) are supported, as well as custom objects which use JSON.mapping or define a new method that accepts a JSON::PullParser and returns an object from it. Union types are supported, if multiple types in the union can be mapped from the JSON, it is undefined which one will be chosen.
The value can also be another hash literal with the following options:
JSON::Any too)true, the property can be Nil. Passing T? as a type has the same effect.null and nilable was not set to true. If the default value creates a new instance of an object (for example [1, 2, 3] or SomeObject.new), a different instance will be used each time a JSON document is parsed.true, emits a null value for nilable properties (by default nulls are not emitted)from_json(JSON::PullParser) and to_json(value, JSON::Builder) as class methods. Examples of converters are Time::Format and Time::EpochConverter for Time.Object.from_json(string_or_io, root))true, will generate a setter for the variable, true by defaulttrue, will generate a getter for the variable, true by defaulttrue, a {{key}}_present? method will be generated when the key was present (even if it has a null value), false by defaultThis macro by default defines getters and setters for each variable (this can be overrided with setter and getter). The mapping doesn't define a constructor accepting these variables as arguments, but you can provide an overload.
The macro basically defines a constructor accepting a JSON::PullParser that reads from it and initializes this type's instance variables. It also defines a to_json(JSON::Builder) method by invoking to_json(JSON::Builder) on each of the properties (unless a converter is specified, in which case to_json(value, JSON::Builder) is invoked).
This macro also declares instance variables of the types given in the mapping.
If strict is true, unknown properties in the JSON document will raise a parse exception. The default is false, so unknown properties are silently ignored.
DEPRECATED use JSON::Serializable instead (the legacy behaviour is also available in a shard at github:crystal-lang/json_mapping.cr)
This is a convenience method to allow invoking JSON.mapping with named arguments instead of with a hash/named-tuple literal.
DEPRECATED use JSON::Serializable instead (the legacy behaviour is also available in a shard at github:crystal-lang/json_mapping.cr)
© 2012–2020 Manas Technology Solutions.
Licensed under the Apache License, Version 2.0.
https://crystal-lang.org/api/0.35.1/JSON.html