If I am getting a JSON response for a cars
endpoint:
{
data: {
cars: [
{ make: "Tesla", model: "S" }
]
}
}
And I have a class Car
:
class Car
JSON.mapping(
make: String,
model: String
)
end
How can I parse the response so that the root goes down two levels? I know that I can do Car.from_json(json_string, "data")
, but cannot find a way to specify another root key.
If there is no way to do this, what would be the simplest way without creating another class just for the cars
level?
There's several approaches you can take here.
One simple, albeit least efficient, is to just parse twice:
cars = Array(Car).from_json(JSON.parse(json)["data"]["cars"].to_json)
Then as you mentioned, you can just create mappings for the outer classes. There's no real faster way compared to what you have:
class Root
JSON.mapping(data: Data)
end
class Data
JSON.mapping(cars: Array(Car))
end
class Car
JSON.mapping(
make: String,
model: String
)
end
cars = Root.from_json(json).data.cars
Or if you prefer using the JSON::Serializable
API:
class Root
include JSON::Serializable
property data : Data
end
class Data
include JSON::Serializable
property cars : Array(Car)
end
class Car
include JSON::Serializable
property make : String
property model : String
end
cars = Root.from_json(json).data.cars
Finally, a last approach is to drive the JSON::PullParser
API directly:
parser = JSON::PullParser.new(json)
cars = nil
parser.on_key("data") do
parser.on_key("cars") do
cars = Array(Car).new(parser)
end
end