It’s not just “hard” to do things correctly, the libraries are explicitly designed for people to do things wrong.
aeson not only expects its users to use
Generic instances, it’s handrolling experience outright sucks. Even running a handrolled parser is a puzzle because the library does not bother exposing a
Parser a -> LazyByteString -> Result a function.
aeson additionally expects every JSON to be 1:1 convertible to its Haskell counterpart (
Value). This makes streaming out of the box impossible in either direction and provides no value whatsoever to the user, who could just use the original
servant doubles down on the “one true instance” idea by assigning a content type to a typeclass. As a result any production API that uses
servant is guaranteed to use
Generic instances to parse and compose one-direction endpoint types, making minor adjustments impossible without manually rewriting the instances.
aeson criticisms apply to virtually every single codec package in the ecosystem, the
servant one is the general line of thinking when designing Haskell applications. The fascinating thing is that all of the bad choices here are at library level, the language provides all the basic tools to do things right.