Crystal: [RFC] Enum JSON string converter

Created on 4 Nov 2020  路  2Comments  路  Source: crystal-lang/crystal

Enums sure are handy for DSLs and protocols, especially with the recent discriminator logic in serialization.
Currently, if an enum is present on a model including JSON::Serializable it serializes to an integer.

I propose Enum::StringConverter JSON converter module.

Usage:

require "json"

struct Body
  include JSON::Serializable

  @[JSON::Field(converter: Enum::StringConverter)]
  getter hint : Example = Example::MemberOne
end

Body.new.to_json                         # => {"hint":"member_one"}
Body.from_json(%({"hint":"member_one"})) # => Body(@hint=Example::MemberOne)

An alternative would be allowing String typed enums, like the following

enum Example : String
  MemberOne
  MemberTwo
end

Example::MemberOne.to_json      # => "member_one"
Example.from_json("member_one") # => Example::MemberOne
feature topicserialization

Most helpful comment

To not forget: The same applies to YAML serialization.

All 2 comments

A string-based converter seems like a great idea. I'm recalling that this was mentioned somewhere before, but can't find it.
We might even consider to make this the default serialization for enums. The currently used enum numbers are in general just an internal representation. In Crystal, enum members also just report their names, not the number.
There is actually a serious problem with using the numbers for serialization: Unless explicitly assigned (like in HTTP::Status), the values can easily change between builds when members are added, removed or reordered.
For example:

enum Foo
  B
  C
end

Foo::C.to_json # => "1"

When reading that serialized value from a program with an additional enum member, it returns a different result:

enum Foo
  B
  C
end

Foo.from_json("1") # => B

Using the names instead of values would be more reliable. Renaming an existing member is far less likely then adding, removing or reordering members. Deserializing a renamed or removed member would also properly fail, not simply return a different member.

To not forget: The same applies to YAML serialization.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pbrusco picture pbrusco  路  3Comments

cjgajard picture cjgajard  路  3Comments

will picture will  路  3Comments

Papierkorb picture Papierkorb  路  3Comments

lgphp picture lgphp  路  3Comments