Version 2 (modified by basvandijk, 13 months ago)

--

Proposal: Add the aeson package to the Haskell Platform

This is a proposal for the aeson package to be included in the next major release of the Haskell platform.

Everyone is invited to review this proposal, following the standard procedure for proposing and reviewing packages.

Review comments should be sent to the libraries mailing list before October 7th, 2013, which is the discussion deadline.

Credits

Proposal author: Bas van Dijk

Package maintainer: Bryan O'Sullivan

The following individuals contributed to the review process:

  • Bas van Dijk
  • ...

Abstract

aeson is a JSON parsing and encoding library optimized for ease of use and high performance.

Documentation and tarball from the hackage page:

http://hackage.haskell.org/package/aeson

Development repo:

https://github.com/bos/aeson

Rationale

Web applications have become prevalent. The primary data interchange format between client and web-server is JSON. In order for Haskell web application servers to communicate with clients, Haskell values need to be encoded to and decoded from JSON documents. The Haskell Platform currently lacks a library that helps with this.

aeson is currently the most popular JSON encoding/decoding library on Hackage, having 185 reverse dependencies at the time of writing. It has good documentation, a test suite and a benchmarking suite.

Introduction to the API

Encoding and decoding are each two-step processes.

  • To encode a value, it is first converted to an abstract syntax tree (AST) called Value, using ToJSON. This generic representation is then encoded as bytes.
  • When decoding a value, the process is reversed: the bytes are converted to an AST, then the FromJSON class is used to convert to the desired type.

For convenience, the encode and decode functions combine both steps.

Multiple combinators are provided to help with encoding and decoding to and from the AST. The following is an example of some of the combinators in action:

data Person = Person
     { name :: Text
     , age  :: Int
     } deriving Show

instance ToJSON Person where
  toJSON person = object 
                  [ "name" .= name person
                  , "age"  .= age  person       
                  ]

instance FromJSON Person where
  parseJSON = withObject "Person" $ \obj ->
                Person <$> obj .: "name"
                       <*> obj .: "age"

The library provides automatic derivation of the toJSON and parseJSON methods using either GHC Generics or Template Haskell. Both ways provide encoding configuration through the Options record.

Design decisions

Here I compare aeson with json, another popular JSON encoding/decoding library for Haskell.

  • aeson encodes to and decodes from ByteStrings instead of Strings like json.
  • aeson represents JSON strings as Text instead of Strings like json.
  • aeson decouples encoding from decoding, i.e. it has separate ToJSON and FromJSON classes. json has one class for both encoding and decoding.
  • aeson uses a HashMap for representing JSON objects. json uses an association list. Whether a HashMap is the best choice remains to be seen. Also see this comment from Bryan.
  • The parseJSON method in aeson returns an abstract parser:
parseJSON :: Value -> Parser a

the similar readJSON method in json on the other hand returns a concrete Result type:

readJSON :: JSValue -> Result a

data Result a = Ok a | Error String

The abstract Parser monad of aeson allows changing the implementation without needing to adapt user's code. The Parser also uses an efficient continuation based parser.

Open issues

  • aeson-0.6.2 currently depends on blaze-builder which is not in the platform. Fortunately aeson HEAD is now using the Builder from bytestring >= 0.10 (it can still use older versions of bytestring by configuring aeson with -fblaze-builder).