5

In JSON.mapping documentation explicitly stated the value of type property should be single type. However, in practice union types also works:

json1 = %q({"ok": true, "result": [{"type": "update", "id": 1}, {"type": "update", "id": 2}]})
json2 = %q({"ok": true, "result": {"type": "message"}})

class Response
  JSON.mapping({
    ok: Bool,
    result: Message | Array(Update)
  })
end

class Update
  JSON.mapping({
    type: String,
    id: Int32
  })
end

class Message
  JSON.mapping({
    type: String
  })
end

Calling Response.from_json on both JSON string will output expected result.

Response.from_json json1

will output:

#<Response:0x10d20ce20
  @ok=true,
  @result=
  [#<Update:0x10d20cc60 @id=1, @type="update">,
   #<Update:0x10d20cbe0 @id=2, @type="update">]>

And

Response.from_json json2

will output:

#<Response:0x10d20c180
  @ok=true,
  @result=#<Message:0x10e241f80 @type="message">>

My question is how does it work? Is it expected behaviour or random unreliable feature?

vtambourine
  • 2,109
  • 3
  • 18
  • 27

1 Answers1

1

This is expected, the documentation is incorrect.

Stephie
  • 3,135
  • 17
  • 22
  • 1
    In that case, how does the macro choose what type to apply on the passing json? Consider following play — https://play.crystal-lang.org/#/r/3b84. `Message` and `Nessage` type are the same, but no matter in what order I specify them in class declaration or in type union, mapper always chooses the `Message`. – vtambourine Dec 29 '17 at 22:57
  • 1
    It's in alphabetical order, it seems. – Stephie Dec 30 '17 at 11:31