How to map parsed JSON as JSON::Any type to custom Object?
In my case, I am working on chat client. Chat API can respond to requests with following JSON:
{"ok" => true,
"result" =>
[{"update_id" => 71058322,
"message" =>
{"message_id" => 20,
"from" => "Benjamin",
"text" => "hey"}}]}
Somewhere inside my API client code I parse these JSON to perform some basic health checks and pass the result to response consumer. In the consumer, I iterate over result array and try to convert each update to appropriate object:
module Types
class Update
JSON.mapping({
update_id: {type: Int32},
message: {type: Message},
})
end
end
module Types
class Message
JSON.mapping({
message_id: Int32,
date: Int32,
text: String,
})
end
end
return unless response["ok"]
response["result"].each do |data|
update = Types::Update.from_json(data)
end
Unfortunately, last line results in compile error:
no overload matches 'JSON::Lexer.new' with type JSON::Any
Apparently, Object.from_json can accept only String JSONs, but not parsed JSON. In my case data is JSON::Any object.
Dirty fix Types::Update.from_json(data.to_json) works, but it looks ridiculous.
What is the proper way to map JSON object to custom type preserving all nested structure?
JSON.mapping doesn't work nicely together with JSON.parse. To solve your problem you can create another mapping Types::Result and parse a hole json using Object.from_json which is even much more convenient to work with:
module Types
class Message
JSON.mapping(
message_id: Int32,
text: String
)
end
class Update
JSON.mapping(
update_id: Int32,
message: Message
)
end
class Result
JSON.mapping(
success: { key: "ok", type: Bool },
updates: { key: "result", type: Array(Update) }
)
end
end
result = Types::Result.from_json string_json
result.success # => true
result.updates.first.message.text # => "hey"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With