Complex JSON deserialization

A more compatible approach could be a JSON::PullParser implementation that traverses a JSON::Any structure instead of parsing JSON directly. :thinking:

I’m trying to to the same; I have a JSON document with two dateTimes within an outer root. If I try to create fields for both, I need to use the same interior key, which creates an error, even though the resulting property has a different name:

  property start_datetime : Time

  @[JSON::Field(converter: TimeToUTC, key: "dateTime", root: "end")]
  property end_datetime : Time```

“start”: {
“dateTime”: “2024-05-19T10:00:00-07:00”,
“timeZone”: “America/Los_Angeles”
},
“end”: {
“dateTime”: “2024-05-19T14:00:00-07:00”,
“timeZone”: “America/Los_Angeles”
}

The problem is using root twice I think.

module TimeToUTC
  def self.from_json(pull : JSON::PullParser) : Time
    time = zone = ""

    pull.read_object do |key|
      case key
      when "dateTime" then time = pull.read_string
      when "timeZone" then zone = pull.read_string
      end
    end

    Time.parse_rfc3339(time).to_utc
  end
end

class Event
  include JSON::Serializable

  @[JSON::Field(converter: TimeToUTC, key: "start")]
  property start_datetime : Time

  @[JSON::Field(converter: TimeToUTC, key: "end")]
  property end_datetime : Time
end

Should do the trick. Where you only provide the key, then can use the converter to parse the object explicitly to extract/build what you need.

I am happy someone show that issue with json, because it give me problems as well. It will be better I thin if the json implementation can handle that (complex structure)

Your code example seems incomplete, but it might be that you’re mixing up key and root.
key is the name of the property in the object, which in your example could be "start" or "end". root is the nested property, which could be "dateTime" or "timeZone".

Offering since this JSON structure looks familiar — if you’re working with the Google Calendar API, I’ve got you covered with this shard.

google = Google::Client.new(
  client_id: ENV["GOOGLE_CLIENT_ID"],
  client_secret: ENV["GOOGLE_CLIENT_SECRET"],
  redirect_uri: ENV["GOOGLE_REDIRECT_URI"],
)

google
  .calendar
  .events
  .list(calendar, oauth_access_token)
2 Likes