Blame Data/Aeson.hs

Packit 9a2dfb
-- |
Packit 9a2dfb
-- Module:      Data.Aeson
Packit 9a2dfb
-- Copyright:   (c) 2011-2016 Bryan O'Sullivan
Packit 9a2dfb
--              (c) 2011 MailRank, Inc.
Packit 9a2dfb
-- License:     BSD3
Packit 9a2dfb
-- Maintainer:  Bryan O'Sullivan <bos@serpentine.com>
Packit 9a2dfb
-- Stability:   experimental
Packit 9a2dfb
-- Portability: portable
Packit 9a2dfb
--
Packit 9a2dfb
-- Types and functions for working efficiently with JSON data.
Packit 9a2dfb
--
Packit 9a2dfb
-- (A note on naming: in Greek mythology, Aeson was the father of Jason.)
Packit 9a2dfb
Packit 9a2dfb
module Data.Aeson
Packit 9a2dfb
    (
Packit 9a2dfb
    -- * How to use this library
Packit 9a2dfb
    -- $use
Packit 9a2dfb
Packit 9a2dfb
    -- ** Writing instances by hand
Packit 9a2dfb
    -- $manual
Packit 9a2dfb
Packit 9a2dfb
    -- ** Working with the AST
Packit 9a2dfb
    -- $ast
Packit 9a2dfb
Packit 9a2dfb
    -- ** Decoding to a Haskell value
Packit 9a2dfb
    -- $haskell
Packit 9a2dfb
Packit 9a2dfb
    -- ** Decoding a mixed-type object
Packit 9a2dfb
    -- $mixed
Packit 9a2dfb
Packit 9a2dfb
    -- * Encoding and decoding
Packit 9a2dfb
    -- $encoding_and_decoding
Packit 9a2dfb
Packit 9a2dfb
    -- ** Direct encoding
Packit 9a2dfb
    -- $encoding
Packit 9a2dfb
      decode
Packit 9a2dfb
    , decode'
Packit 9a2dfb
    , eitherDecode
Packit 9a2dfb
    , eitherDecode'
Packit 9a2dfb
    , encode
Packit 9a2dfb
    -- ** Variants for strict bytestrings
Packit 9a2dfb
    , decodeStrict
Packit 9a2dfb
    , decodeStrict'
Packit 9a2dfb
    , eitherDecodeStrict
Packit 9a2dfb
    , eitherDecodeStrict'
Packit 9a2dfb
    -- * Core JSON types
Packit 9a2dfb
    , Value(..)
Packit 9a2dfb
    , Encoding
Packit 9a2dfb
    , fromEncoding
Packit 9a2dfb
    , Array
Packit 9a2dfb
    , Object
Packit 9a2dfb
    -- * Convenience types
Packit 9a2dfb
    , DotNetTime(..)
Packit 9a2dfb
    -- * Type conversion
Packit 9a2dfb
    , FromJSON(..)
Packit 9a2dfb
    , Result(..)
Packit 9a2dfb
    , fromJSON
Packit 9a2dfb
    , ToJSON(..)
Packit 9a2dfb
    , KeyValue(..)
Packit 9a2dfb
    -- ** Keys for maps
Packit 9a2dfb
    , ToJSONKey(..)
Packit 9a2dfb
    , ToJSONKeyFunction(..)
Packit 9a2dfb
    , FromJSONKey(..)
Packit 9a2dfb
    , FromJSONKeyFunction(..)
Packit 9a2dfb
    -- ** Liftings to unary and binary type constructors
Packit 9a2dfb
    , FromJSON1(..)
Packit 9a2dfb
    , parseJSON1
Packit 9a2dfb
    , FromJSON2(..)
Packit 9a2dfb
    , parseJSON2
Packit 9a2dfb
    , ToJSON1(..)
Packit 9a2dfb
    , toJSON1
Packit 9a2dfb
    , toEncoding1
Packit 9a2dfb
    , ToJSON2(..)
Packit 9a2dfb
    , toJSON2
Packit 9a2dfb
    , toEncoding2
Packit 9a2dfb
    -- ** Generic JSON classes and options
Packit 9a2dfb
    , GFromJSON(..)
Packit 9a2dfb
    , FromArgs(..)
Packit 9a2dfb
    , GToJSON
Packit 9a2dfb
    , GToEncoding
Packit 9a2dfb
    , ToArgs(..)
Packit 9a2dfb
    , Zero
Packit 9a2dfb
    , One
Packit 9a2dfb
    , genericToJSON
Packit 9a2dfb
    , genericLiftToJSON
Packit 9a2dfb
    , genericToEncoding
Packit 9a2dfb
    , genericLiftToEncoding
Packit 9a2dfb
    , genericParseJSON
Packit 9a2dfb
    , genericLiftParseJSON
Packit 9a2dfb
    -- ** Generic and TH encoding configuration
Packit 9a2dfb
    , Options
Packit 9a2dfb
    , defaultOptions
Packit 9a2dfb
    -- *** Options fields
Packit 9a2dfb
    -- $optionsFields
Packit 9a2dfb
    , fieldLabelModifier
Packit 9a2dfb
    , constructorTagModifier
Packit 9a2dfb
    , allNullaryToStringTag
Packit 9a2dfb
    , omitNothingFields
Packit 9a2dfb
    , sumEncoding
Packit 9a2dfb
    , unwrapUnaryRecords
Packit 9a2dfb
    , tagSingleConstructors
Packit 9a2dfb
    -- *** Options utilities
Packit 9a2dfb
    , SumEncoding(..)
Packit 9a2dfb
    , camelTo2
Packit 9a2dfb
    , defaultTaggedObject
Packit 9a2dfb
Packit 9a2dfb
    -- * Inspecting @'Value's@
Packit 9a2dfb
    , withObject
Packit 9a2dfb
    , withText
Packit 9a2dfb
    , withArray
Packit 9a2dfb
    , withNumber
Packit 9a2dfb
    , withScientific
Packit 9a2dfb
    , withBool
Packit 9a2dfb
    , withEmbeddedJSON
Packit 9a2dfb
    -- * Constructors and accessors
Packit 9a2dfb
    , Series
Packit 9a2dfb
    , pairs
Packit 9a2dfb
    , foldable
Packit 9a2dfb
    , (.:)
Packit 9a2dfb
    , (.:?)
Packit 9a2dfb
    , (.:!)
Packit 9a2dfb
    , (.!=)
Packit 9a2dfb
    , object
Packit 9a2dfb
    -- * Parsing
Packit 9a2dfb
    , json
Packit 9a2dfb
    , json'
Packit 9a2dfb
    ) where
Packit 9a2dfb
Packit 9a2dfb
import Prelude ()
Packit 9a2dfb
import Prelude.Compat
Packit 9a2dfb
Packit 9a2dfb
import Data.Aeson.Types.FromJSON (ifromJSON)
Packit 9a2dfb
import Data.Aeson.Encoding (encodingToLazyByteString)
Packit 9a2dfb
import Data.Aeson.Parser.Internal (decodeWith, decodeStrictWith, eitherDecodeWith, eitherDecodeStrictWith, jsonEOF, json, jsonEOF', json')
Packit 9a2dfb
import Data.Aeson.Types
Packit 9a2dfb
import Data.Aeson.Types.Internal (JSONPath, formatError)
Packit 9a2dfb
import qualified Data.ByteString as B
Packit 9a2dfb
import qualified Data.ByteString.Lazy as L
Packit 9a2dfb
Packit 9a2dfb
-- | Efficiently serialize a JSON value as a lazy 'L.ByteString'.
Packit 9a2dfb
--
Packit 9a2dfb
-- This is implemented in terms of the 'ToJSON' class's 'toEncoding' method.
Packit 9a2dfb
encode :: (ToJSON a) => a -> L.ByteString
Packit 9a2dfb
encode = encodingToLazyByteString . toEncoding
Packit 9a2dfb
Packit 9a2dfb
-- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.
Packit 9a2dfb
-- If this fails due to incomplete or invalid input, 'Nothing' is
Packit 9a2dfb
-- returned.
Packit 9a2dfb
--
Packit 9a2dfb
-- The input must consist solely of a JSON document, with no trailing
Packit 9a2dfb
-- data except for whitespace.
Packit 9a2dfb
--
Packit 9a2dfb
-- This function parses immediately, but defers conversion.  See
Packit 9a2dfb
-- 'json' for details.
Packit 9a2dfb
decode :: (FromJSON a) => L.ByteString -> Maybe a
Packit 9a2dfb
decode = decodeWith jsonEOF fromJSON
Packit 9a2dfb
{-# INLINE decode #-}
Packit 9a2dfb
Packit 9a2dfb
-- | Efficiently deserialize a JSON value from a strict 'B.ByteString'.
Packit 9a2dfb
-- If this fails due to incomplete or invalid input, 'Nothing' is
Packit 9a2dfb
-- returned.
Packit 9a2dfb
--
Packit 9a2dfb
-- The input must consist solely of a JSON document, with no trailing
Packit 9a2dfb
-- data except for whitespace.
Packit 9a2dfb
--
Packit 9a2dfb
-- This function parses immediately, but defers conversion.  See
Packit 9a2dfb
-- 'json' for details.
Packit 9a2dfb
decodeStrict :: (FromJSON a) => B.ByteString -> Maybe a
Packit 9a2dfb
decodeStrict = decodeStrictWith jsonEOF fromJSON
Packit 9a2dfb
{-# INLINE decodeStrict #-}
Packit 9a2dfb
Packit 9a2dfb
-- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.
Packit 9a2dfb
-- If this fails due to incomplete or invalid input, 'Nothing' is
Packit 9a2dfb
-- returned.
Packit 9a2dfb
--
Packit 9a2dfb
-- The input must consist solely of a JSON document, with no trailing
Packit 9a2dfb
-- data except for whitespace.
Packit 9a2dfb
--
Packit 9a2dfb
-- This function parses and performs conversion immediately.  See
Packit 9a2dfb
-- 'json'' for details.
Packit 9a2dfb
decode' :: (FromJSON a) => L.ByteString -> Maybe a
Packit 9a2dfb
decode' = decodeWith jsonEOF' fromJSON
Packit 9a2dfb
{-# INLINE decode' #-}
Packit 9a2dfb
Packit 9a2dfb
-- | Efficiently deserialize a JSON value from a strict 'B.ByteString'.
Packit 9a2dfb
-- If this fails due to incomplete or invalid input, 'Nothing' is
Packit 9a2dfb
-- returned.
Packit 9a2dfb
--
Packit 9a2dfb
-- The input must consist solely of a JSON document, with no trailing
Packit 9a2dfb
-- data except for whitespace.
Packit 9a2dfb
--
Packit 9a2dfb
-- This function parses and performs conversion immediately.  See
Packit 9a2dfb
-- 'json'' for details.
Packit 9a2dfb
decodeStrict' :: (FromJSON a) => B.ByteString -> Maybe a
Packit 9a2dfb
decodeStrict' = decodeStrictWith jsonEOF' fromJSON
Packit 9a2dfb
{-# INLINE decodeStrict' #-}
Packit 9a2dfb
Packit 9a2dfb
eitherFormatError :: Either (JSONPath, String) a -> Either String a
Packit 9a2dfb
eitherFormatError = either (Left . uncurry formatError) Right
Packit 9a2dfb
{-# INLINE eitherFormatError #-}
Packit 9a2dfb
Packit 9a2dfb
-- | Like 'decode' but returns an error message when decoding fails.
Packit 9a2dfb
eitherDecode :: (FromJSON a) => L.ByteString -> Either String a
Packit 9a2dfb
eitherDecode = eitherFormatError . eitherDecodeWith jsonEOF ifromJSON
Packit 9a2dfb
{-# INLINE eitherDecode #-}
Packit 9a2dfb
Packit 9a2dfb
-- | Like 'decodeStrict' but returns an error message when decoding fails.
Packit 9a2dfb
eitherDecodeStrict :: (FromJSON a) => B.ByteString -> Either String a
Packit 9a2dfb
eitherDecodeStrict =
Packit 9a2dfb
  eitherFormatError . eitherDecodeStrictWith jsonEOF ifromJSON
Packit 9a2dfb
{-# INLINE eitherDecodeStrict #-}
Packit 9a2dfb
Packit 9a2dfb
-- | Like 'decode'' but returns an error message when decoding fails.
Packit 9a2dfb
eitherDecode' :: (FromJSON a) => L.ByteString -> Either String a
Packit 9a2dfb
eitherDecode' = eitherFormatError . eitherDecodeWith jsonEOF' ifromJSON
Packit 9a2dfb
{-# INLINE eitherDecode' #-}
Packit 9a2dfb
Packit 9a2dfb
-- | Like 'decodeStrict'' but returns an error message when decoding fails.
Packit 9a2dfb
eitherDecodeStrict' :: (FromJSON a) => B.ByteString -> Either String a
Packit 9a2dfb
eitherDecodeStrict' =
Packit 9a2dfb
  eitherFormatError . eitherDecodeStrictWith jsonEOF' ifromJSON
Packit 9a2dfb
{-# INLINE eitherDecodeStrict' #-}
Packit 9a2dfb
Packit 9a2dfb
-- $use
Packit 9a2dfb
--
Packit 9a2dfb
-- This section contains basic information on the different ways to
Packit 9a2dfb
-- work with data using this library. These range from simple but
Packit 9a2dfb
-- inflexible, to complex but flexible.
Packit 9a2dfb
--
Packit 9a2dfb
-- The most common way to use the library is to define a data type,
Packit 9a2dfb
-- corresponding to some JSON data you want to work with, and then
Packit 9a2dfb
-- write either a 'FromJSON' instance, a to 'ToJSON' instance, or both
Packit 9a2dfb
-- for that type.
Packit 9a2dfb
--
Packit 9a2dfb
-- For example, given this JSON data:
Packit 9a2dfb
--
Packit 9a2dfb
-- > { "name": "Joe", "age": 12 }
Packit 9a2dfb
--
Packit 9a2dfb
-- we create a matching data type:
Packit 9a2dfb
--
Packit 9a2dfb
-- > {-# LANGUAGE DeriveGeneric #-}
Packit 9a2dfb
-- >
Packit 9a2dfb
-- > import GHC.Generics
Packit 9a2dfb
-- >
Packit 9a2dfb
-- > data Person = Person {
Packit 9a2dfb
-- >       name :: Text
Packit 9a2dfb
-- >     , age  :: Int
Packit 9a2dfb
-- >     } deriving (Generic, Show)
Packit 9a2dfb
--
Packit 9a2dfb
-- The @LANGUAGE@ pragma and 'Generic' instance let us write empty
Packit 9a2dfb
-- 'FromJSON' and 'ToJSON' instances for which the compiler will
Packit 9a2dfb
-- generate sensible default implementations.
Packit 9a2dfb
--
Packit 9a2dfb
-- @
Packit 9a2dfb
-- instance 'ToJSON' Person where
Packit 9a2dfb
--     \-- No need to provide a 'toJSON' implementation.
Packit 9a2dfb
--
Packit 9a2dfb
--     \-- For efficiency, we write a simple 'toEncoding' implementation, as
Packit 9a2dfb
--     \-- the default version uses 'toJSON'.
Packit 9a2dfb
--     'toEncoding' = 'genericToEncoding' 'defaultOptions'
Packit 9a2dfb
--
Packit 9a2dfb
-- instance 'FromJSON' Person
Packit 9a2dfb
--     \-- No need to provide a 'parseJSON' implementation.
Packit 9a2dfb
-- @
Packit 9a2dfb
--
Packit 9a2dfb
-- We can now encode a value like so:
Packit 9a2dfb
--
Packit 9a2dfb
-- > >>> encode (Person {name = "Joe", age = 12})
Packit 9a2dfb
-- > "{\"name\":\"Joe\",\"age\":12}"
Packit 9a2dfb
Packit 9a2dfb
-- $manual
Packit 9a2dfb
--
Packit 9a2dfb
-- When necessary, we can write 'ToJSON' and 'FromJSON' instances by
Packit 9a2dfb
-- hand.  This is valuable when the JSON-on-the-wire and Haskell data
Packit 9a2dfb
-- are different or otherwise need some more carefully managed
Packit 9a2dfb
-- translation.  Let's revisit our JSON data:
Packit 9a2dfb
--
Packit 9a2dfb
-- > { "name": "Joe", "age": 12 }
Packit 9a2dfb
--
Packit 9a2dfb
-- We once again create a matching data type, without bothering to add
Packit 9a2dfb
-- a 'Generic' instance this time:
Packit 9a2dfb
--
Packit 9a2dfb
-- > data Person = Person {
Packit 9a2dfb
-- >       name :: Text
Packit 9a2dfb
-- >     , age  :: Int
Packit 9a2dfb
-- >     } deriving Show
Packit 9a2dfb
--
Packit 9a2dfb
-- To decode data, we need to define a 'FromJSON' instance:
Packit 9a2dfb
--
Packit 9a2dfb
-- > {-# LANGUAGE OverloadedStrings #-}
Packit 9a2dfb
-- >
Packit 9a2dfb
-- > instance FromJSON Person where
Packit 9a2dfb
-- >     parseJSON = withObject "Person" $ \v -> Person
Packit 9a2dfb
-- >         <$> v .: "name"
Packit 9a2dfb
-- >         <*> v .: "age"
Packit 9a2dfb
--
Packit 9a2dfb
-- We can now parse the JSON data like so:
Packit 9a2dfb
--
Packit 9a2dfb
-- > >>> decode "{\"name\":\"Joe\",\"age\":12}" :: Maybe Person
Packit 9a2dfb
-- > Just (Person {name = "Joe", age = 12})
Packit 9a2dfb
--
Packit 9a2dfb
-- To encode data, we need to define a 'ToJSON' instance. Let's begin
Packit 9a2dfb
-- with an instance written entirely by hand.
Packit 9a2dfb
--
Packit 9a2dfb
-- @
Packit 9a2dfb
-- instance ToJSON Person where
Packit 9a2dfb
--     \-- this generates a 'Value'
Packit 9a2dfb
--     'toJSON' (Person name age) =
Packit 9a2dfb
--         'object' [\"name\" '.=' name, \"age\" '.=' age]
Packit 9a2dfb
--
Packit 9a2dfb
--     \-- this encodes directly to a bytestring Builder
Packit 9a2dfb
--     'toEncoding' (Person name age) =
Packit 9a2dfb
--         'pairs' (\"name\" '.=' 'name' '<>' \"age\" '.=' age)
Packit 9a2dfb
-- @
Packit 9a2dfb
--
Packit 9a2dfb
-- We can now encode a value like so:
Packit 9a2dfb
--
Packit 9a2dfb
-- > >>> encode (Person {name = "Joe", age = 12})
Packit 9a2dfb
-- > "{\"name\":\"Joe\",\"age\":12}"
Packit 9a2dfb
--
Packit 9a2dfb
-- There are predefined 'FromJSON' and 'ToJSON' instances for many
Packit 9a2dfb
-- types. Here's an example using lists and 'Int's:
Packit 9a2dfb
--
Packit 9a2dfb
-- > >>> decode "[1,2,3]" :: Maybe [Int]
Packit 9a2dfb
-- > Just [1,2,3]
Packit 9a2dfb
--
Packit 9a2dfb
-- And here's an example using the 'Data.Map.Map' type to get a map of
Packit 9a2dfb
-- 'Int's.
Packit 9a2dfb
--
Packit 9a2dfb
-- > >>> decode "{\"foo\":1,\"bar\":2}" :: Maybe (Map String Int)
Packit 9a2dfb
-- > Just (fromList [("bar",2),("foo",1)])
Packit 9a2dfb
Packit 9a2dfb
-- While the notes below focus on decoding, you can apply almost the
Packit 9a2dfb
-- same techniques to /encoding/ data. (The main difference is that
Packit 9a2dfb
-- encoding always succeeds, but decoding has to handle the
Packit 9a2dfb
-- possibility of failure, where an input doesn't match our
Packit 9a2dfb
-- expectations.)
Packit 9a2dfb
--
Packit 9a2dfb
-- See the documentation of 'FromJSON' and 'ToJSON' for some examples
Packit 9a2dfb
-- of how you can automatically derive instances in many common
Packit 9a2dfb
-- circumstances.
Packit 9a2dfb
Packit 9a2dfb
-- $ast
Packit 9a2dfb
--
Packit 9a2dfb
-- Sometimes you want to work with JSON data directly, without first
Packit 9a2dfb
-- converting it to a custom data type. This can be useful if you want
Packit 9a2dfb
-- to e.g. convert JSON data to YAML data, without knowing what the
Packit 9a2dfb
-- contents of the original JSON data was. The 'Value' type, which is
Packit 9a2dfb
-- an instance of 'FromJSON', is used to represent an arbitrary JSON
Packit 9a2dfb
-- AST (abstract syntax tree). Example usage:
Packit 9a2dfb
--
Packit 9a2dfb
-- > >>> decode "{\"foo\": 123}" :: Maybe Value
Packit 9a2dfb
-- > Just (Object (fromList [("foo",Number 123)]))
Packit 9a2dfb
--
Packit 9a2dfb
-- > >>> decode "{\"foo\": [\"abc\",\"def\"]}" :: Maybe Value
Packit 9a2dfb
-- > Just (Object (fromList [("foo",Array (fromList [String "abc",String "def"]))]))
Packit 9a2dfb
--
Packit 9a2dfb
-- Once you have a 'Value' you can write functions to traverse it and
Packit 9a2dfb
-- make arbitrary transformations.
Packit 9a2dfb
Packit 9a2dfb
-- $haskell
Packit 9a2dfb
--
Packit 9a2dfb
-- We can decode to any instance of 'FromJSON':
Packit 9a2dfb
--
Packit 9a2dfb
-- > λ> decode "[1,2,3]" :: Maybe [Int]
Packit 9a2dfb
-- > Just [1,2,3]
Packit 9a2dfb
--
Packit 9a2dfb
-- Alternatively, there are instances for standard data types, so you
Packit 9a2dfb
-- can use them directly. For example, use the 'Data.Map.Map' type to
Packit 9a2dfb
-- get a map of 'Int's.
Packit 9a2dfb
--
Packit 9a2dfb
-- > λ> import Data.Map
Packit 9a2dfb
-- > λ> decode "{\"foo\":1,\"bar\":2}" :: Maybe (Map String Int)
Packit 9a2dfb
-- > Just (fromList [("bar",2),("foo",1)])
Packit 9a2dfb
Packit 9a2dfb
-- $mixed
Packit 9a2dfb
--
Packit 9a2dfb
-- The above approach with maps of course will not work for mixed-type
Packit 9a2dfb
-- objects that don't follow a strict schema, but there are a couple
Packit 9a2dfb
-- of approaches available for these.
Packit 9a2dfb
--
Packit 9a2dfb
-- The 'Object' type contains JSON objects:
Packit 9a2dfb
--
Packit 9a2dfb
-- > λ> decode "{\"name\":\"Dave\",\"age\":2}" :: Maybe Object
Packit 9a2dfb
-- > Just (fromList [("name",String "Dave"),("age",Number 2)])
Packit 9a2dfb
--
Packit 9a2dfb
-- You can extract values from it with a parser using 'parse',
Packit 9a2dfb
-- 'parseEither' or, in this example, 'parseMaybe':
Packit 9a2dfb
--
Packit 9a2dfb
-- > λ> do result <- decode "{\"name\":\"Dave\",\"age\":2}"
Packit 9a2dfb
-- >       flip parseMaybe result $ \obj -> do
Packit 9a2dfb
-- >         age <- obj .: "age"
Packit 9a2dfb
-- >         name <- obj .: "name"
Packit 9a2dfb
-- >         return (name ++ ": " ++ show (age*2))
Packit 9a2dfb
-- >
Packit 9a2dfb
-- > Just "Dave: 4"
Packit 9a2dfb
--
Packit 9a2dfb
-- Considering that any type that implements 'FromJSON' can be used
Packit 9a2dfb
-- here, this is quite a powerful way to parse JSON. See the
Packit 9a2dfb
-- documentation in 'FromJSON' for how to implement this class for
Packit 9a2dfb
-- your own data types.
Packit 9a2dfb
--
Packit 9a2dfb
-- The downside is that you have to write the parser yourself; the
Packit 9a2dfb
-- upside is that you have complete control over the way the JSON is
Packit 9a2dfb
-- parsed.
Packit 9a2dfb
Packit 9a2dfb
-- $encoding_and_decoding
Packit 9a2dfb
--
Packit 9a2dfb
-- Decoding is a two-step process.
Packit 9a2dfb
--
Packit 9a2dfb
-- * When decoding a value, the process is reversed: the bytes are
Packit 9a2dfb
--   converted to a 'Value', then the 'FromJSON' class is used to
Packit 9a2dfb
--   convert to the desired type.
Packit 9a2dfb
--
Packit 9a2dfb
-- There are two ways to encode a value.
Packit 9a2dfb
--
Packit 9a2dfb
-- * Convert to a 'Value' using 'toJSON', then possibly further
Packit 9a2dfb
--   encode.  This was the only method available in aeson 0.9 and
Packit 9a2dfb
--   earlier.
Packit 9a2dfb
--
Packit 9a2dfb
-- * Directly encode (to what will become a 'L.ByteString') using
Packit 9a2dfb
--   'toEncoding'.  This is much more efficient (about 3x faster, and
Packit 9a2dfb
--   less memory intensive besides), but is only available in aeson
Packit 9a2dfb
--   0.10 and newer.
Packit 9a2dfb
--
Packit 9a2dfb
-- For convenience, the 'encode' and 'decode' functions combine both
Packit 9a2dfb
-- steps.
Packit 9a2dfb
Packit 9a2dfb
-- $encoding
Packit 9a2dfb
--
Packit 9a2dfb
-- In older versions of this library, encoding a Haskell value
Packit 9a2dfb
-- involved converting to an intermediate 'Value', then encoding that.
Packit 9a2dfb
--
Packit 9a2dfb
-- A \"direct\" encoder converts straight from a source Haskell value
Packit 9a2dfb
-- to a 'BL.ByteString' without constructing an intermediate 'Value'.
Packit 9a2dfb
-- This approach is faster than 'toJSON', and allocates less memory.
Packit 9a2dfb
-- The 'toEncoding' method makes it possible to implement direct
Packit 9a2dfb
-- encoding with low memory overhead.
Packit 9a2dfb
--
Packit 9a2dfb
-- To complicate matters, the default implementation of 'toEncoding'
Packit 9a2dfb
-- uses 'toJSON'.  Why?  The 'toEncoding' method was added to this
Packit 9a2dfb
-- library much more recently than 'toJSON'.  Using 'toJSON' ensures
Packit 9a2dfb
-- that packages written against older versions of this library will
Packit 9a2dfb
-- compile and produce correct output, but they will not see any
Packit 9a2dfb
-- speedup from direct encoding.
Packit 9a2dfb
--
Packit 9a2dfb
-- To write a minimal implementation of direct encoding, your type
Packit 9a2dfb
-- must implement GHC's 'Generic' class, and your code should look
Packit 9a2dfb
-- like this:
Packit 9a2dfb
--
Packit 9a2dfb
-- @
Packit 9a2dfb
--     'toEncoding' = 'genericToEncoding' 'defaultOptions'
Packit 9a2dfb
-- @
Packit 9a2dfb
--
Packit 9a2dfb
-- What if you have more elaborate encoding needs?  For example,
Packit 9a2dfb
-- perhaps you need to change the names of object keys, omit parts of
Packit 9a2dfb
-- a value.
Packit 9a2dfb
--
Packit 9a2dfb
-- To encode to a JSON \"object\", use the 'pairs' function.
Packit 9a2dfb
--
Packit 9a2dfb
-- @
Packit 9a2dfb
--     'toEncoding' (Person name age) =
Packit 9a2dfb
--         'pairs' (\"name\" '.=' 'name' '<>' \"age\" '.=' age)
Packit 9a2dfb
-- @
Packit 9a2dfb
--
Packit 9a2dfb
-- Any container type that implements 'Foldable' can be encoded to a
Packit 9a2dfb
-- JSON \"array\" using 'foldable'.
Packit 9a2dfb
--
Packit 9a2dfb
-- > > import Data.Sequence as Seq
Packit 9a2dfb
-- > > encode (Seq.fromList [1,2,3])
Packit 9a2dfb
-- > "[1,2,3]"