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 LazyByteString
.
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 aeson
's 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.