aeson icon indicating copy to clipboard operation
aeson copied to clipboard

[Docs] Encourage manual To/FromJSON instances

Open imalsogreg opened this issue 3 years ago • 5 comments

There's a convention that suggests avoiding Generic aeson instances because we more commonly (a) add JSON instances to Haskell types used in business logic, and less commonly (b) create a new type whose main job is to represent the encoding of some JSON that we don't control. In that more common case, generic instances lead to backward and forward compatibility issues as the types change with business needs. And we don't like to bloat business types with the Maybe fields needed to achieve compatibility.

Would you be open to a haddock PR that prioritizes the explanation of manual ToJSON and FromJSON instances - with a note about Generic implementations (how and when to use them)?

imalsogreg avatar May 30 '21 01:05 imalsogreg

I'm not against.

The current docs say

Writing instances by hand

When necessary, we can write ToJSON and FromJSON instances by hand. This is valuable when the JSON-on-the-wire and Haskell data are different or otherwise need some more carefully managed translation. Let's revisit our JSON data:

etc.

Would you change that, or do you have something else in mind?

phadej avatar May 30 '21 01:05 phadej

The key to using generic instances is to have separate types for the json representation and business logic. With that you just need to write normal functions converting between the two rather than having to write manual json instances. I think the documented recommendation is good, but it should be clarified.

bergmark avatar May 30 '21 03:05 bergmark

@phadej Yep, I would change the order to start with manual instances, mentioning Generic instances and @bergmark's special-purpose types and conversion functions later. What do you think?

imalsogreg avatar Jun 01 '21 13:06 imalsogreg

I don't know if it is worth including in the docs but one can also try to use registry-aeson (disclaimer: I'm the author of that library). This library supports the creation of encoders / decoders via TemplateHaskell but also provides a way to wire / rewire them in a type directed manner (a bit like type classes do).

With this library it is quite easy to maintain just one data model and change only the encoders/decoders which need to evolve when the data model evolves. It is also possible to support several versions of the encoded data when several versions of the protocol need to coexist on the wire.

Please ask questions on the registry-aeson repository if you want any clarification.

etorreborre avatar Jun 08 '22 11:06 etorreborre

JSON is merely an encoding, and no business logic should change how exactly types get serialized. By employing manual serialization you also force API consumers to employ manual deserialization. I (and probably majority of other developers) would prefer APIs to work in RPC fashion, with no manual intervention, even at the cost of minor loss of readability and performance.

TLDR: please, don't encourage anyone to do manual To/FromJSON instances.

reverofevil avatar Feb 22 '23 06:02 reverofevil