3-- Copyright: (c) 2011-2016 Bryan O'Sullivan
4-- (c) 2011 MailRank, Inc.
6-- Maintainer: Bryan O'Sullivan <bos@serpentine.com>
7-- Stability: experimental
8-- Portability: portable
10-- Types and functions for working efficiently with JSON data.
12-- (A note on naming: in Greek mythology, Aeson was the father of Jason.)
16 -- * How to use this library
19 -- ** Writing instances by hand
22 -- ** Working with the AST
25 -- ** Decoding to a Haskell value
28 -- ** Decoding a mixed-type object
31 -- * Encoding and decoding
32 -- $encoding_and_decoding
41 -- ** Variants for strict bytestrings
52 -- * Convenience types
60 -- ** Generic JSON classes and options
69 -- * Inspecting @'Value's@
76 -- * Constructors and accessors
90import Data.Aeson.Encode (encode)
91import Data.Aeson.Parser.Internal (decodeWith, decodeStrictWith,
92 eitherDecodeWith, eitherDecodeStrictWith,
93 jsonEOF, json, jsonEOF', json')
94import Data.Aeson.Types
95import Data.Aeson.Types.Instances (ifromJSON)
96import Data.Aeson.Types.Internal (JSONPath, formatError)
97import qualified Data.ByteString as B
98import qualified Data.ByteString.Lazy as L
100-- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.
101-- If this fails due to incomplete or invalid input, 'Nothing' is
104-- The input must consist solely of a JSON document, with no trailing
105-- data except for whitespace.
107-- This function parses immediately, but defers conversion. See
108-- 'json' for details.
109decode :: (FromJSON a) => L.ByteString -> Maybe a
110decode = decodeWith jsonEOF fromJSON
113-- | Efficiently deserialize a JSON value from a strict 'B.ByteString'.
114-- If this fails due to incomplete or invalid input, 'Nothing' is
117-- The input must consist solely of a JSON document, with no trailing
118-- data except for whitespace.
120-- This function parses immediately, but defers conversion. See
121-- 'json' for details.
122decodeStrict :: (FromJSON a) => B.ByteString -> Maybe a
123decodeStrict = decodeStrictWith jsonEOF fromJSON
124{-# INLINE decodeStrict #-}
126-- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.
127-- If this fails due to incomplete or invalid input, 'Nothing' is
130-- The input must consist solely of a JSON document, with no trailing
131-- data except for whitespace.
133-- This function parses and performs conversion immediately. See
134-- 'json'' for details.
135decode' :: (FromJSON a) => L.ByteString -> Maybe a
136decode' = decodeWith jsonEOF' fromJSON
137{-# INLINE decode' #-}
139-- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.
140-- If this fails due to incomplete or invalid input, 'Nothing' is
143-- The input must consist solely of a JSON document, with no trailing
144-- data except for whitespace.
146-- This function parses and performs conversion immediately. See
147-- 'json'' for details.
148decodeStrict' :: (FromJSON a) => B.ByteString -> Maybe a
149decodeStrict' = decodeStrictWith jsonEOF' fromJSON
150{-# INLINE decodeStrict' #-}
152eitherFormatError :: Either (JSONPath, String) a -> Either String a
153eitherFormatError = either (Left . uncurry formatError) Right
154{-# INLINE eitherFormatError #-}
156-- | Like 'decode' but returns an error message when decoding fails.
157eitherDecode :: (FromJSON a) => L.ByteString -> Either String a
158eitherDecode = eitherFormatError . eitherDecodeWith jsonEOF ifromJSON
159{-# INLINE eitherDecode #-}
161-- | Like 'decodeStrict' but returns an error message when decoding fails.
162eitherDecodeStrict :: (FromJSON a) => B.ByteString -> Either String a
164 eitherFormatError . eitherDecodeStrictWith jsonEOF ifromJSON
165{-# INLINE eitherDecodeStrict #-}
167-- | Like 'decode'' but returns an error message when decoding fails.
168eitherDecode' :: (FromJSON a) => L.ByteString -> Either String a
169eitherDecode' = eitherFormatError . eitherDecodeWith jsonEOF' ifromJSON
170{-# INLINE eitherDecode' #-}
172-- | Like 'decodeStrict'' but returns an error message when decoding fails.
173eitherDecodeStrict' :: (FromJSON a) => B.ByteString -> Either String a
175 eitherFormatError . eitherDecodeStrictWith jsonEOF' ifromJSON
176{-# INLINE eitherDecodeStrict' #-}
180-- This section contains basic information on the different ways to
181-- work with data using this library. These range from simple but
182-- inflexible, to complex but flexible.
184-- The most common way to use the library is to define a data type,
185-- corresponding to some JSON data you want to work with, and then
186-- write either a 'FromJSON' instance, a to 'ToJSON' instance, or both
189-- For example, given this JSON data:
191-- > { "name": "Joe", "age": 12 }
193-- we create a matching data type:
195-- > {-# LANGUAGE DeriveGeneric #-}
197-- > import GHC.Generics
199-- > data Person = Person {
202-- > } deriving (Generic, Show)
204-- The @LANGUAGE@ pragma and 'Generic' instance let us write empty
205-- 'FromJSON' and 'ToJSON' instances for which the compiler will
206-- generate sensible default implementations.
209-- instance 'ToJSON' Person where
210-- \-- No need to provide a 'toJSON' implementation.
212-- \-- For efficiency, we write a simple 'toEncoding' implementation, as
213-- \-- the default version uses 'toJSON'.
214-- 'toEncoding' = 'genericToEncoding' 'defaultOptions'
216-- instance 'FromJSON' Person
217-- \-- No need to provide a 'parseJSON' implementation.
220-- We can now encode a value like so:
222-- > >>> encode (Person {name = "Joe", age = 12})
223-- > "{\"name\":\"Joe\",\"age\":12}"
227-- When necessary, we can write 'ToJSON' and 'FromJSON' instances by
228-- hand. This is valuable when the JSON-on-the-wire and Haskell data
229-- are different or otherwise need some more carefully managed
230-- translation. Let's revisit our JSON data:
232-- > { "name": "Joe", "age": 12 }
234-- We once again create a matching data type, without bothering to add
235-- a 'Generic' instance this time:
237-- > data Person = Person {
242-- To decode data, we need to define a 'FromJSON' instance:
244-- > {-# LANGUAGE OverloadedStrings #-}
246-- > instance FromJSON Person where
247-- > parseJSON (Object v) = Person <$>
250-- > -- A non-Object value is of the wrong type, so fail.
251-- > parseJSON _ = empty
253-- We can now parse the JSON data like so:
255-- > >>> decode "{\"name\":\"Joe\",\"age\":12}" :: Maybe Person
256-- > Just (Person {name = "Joe", age = 12})
258-- To encode data, we need to define a 'ToJSON' instance. Let's begin
259-- with an instance written entirely by hand.
262-- instance ToJSON Person where
263-- \-- this generates a 'Value'
264-- 'toJSON' (Person name age) =
265-- 'object' [\"name\" '.=' name, \"age\" '.=' age]
267-- \-- this encodes directly to a bytestring Builder
268-- 'toEncoding' (Person name age) =
269-- 'pairs' (\"name\" '.=' 'name' '<>' \"age\" '.=' age)
272-- We can now encode a value like so:
274-- > >>> encode (Person {name = "Joe", age = 12})
275-- > "{\"name\":\"Joe\",\"age\":12}"
277-- There are predefined 'FromJSON' and 'ToJSON' instances for many
278-- types. Here's an example using lists and 'Int's:
280-- > >>> decode "[1,2,3]" :: Maybe [Int]
283-- And here's an example using the 'Data.Map.Map' type to get a map of
286-- > >>> decode "{\"foo\":1,\"bar\":2}" :: Maybe (Map String Int)
287-- > Just (fromList [("bar",2),("foo",1)])
289-- While the notes below focus on decoding, you can apply almost the
290-- same techniques to /encoding/ data. (The main difference is that
291-- encoding always succeeds, but decoding has to handle the
292-- possibility of failure, where an input doesn't match our
295-- See the documentation of 'FromJSON' and 'ToJSON' for some examples
296-- of how you can automatically derive instances in many common
301-- Sometimes you want to work with JSON data directly, without first
302-- converting it to a custom data type. This can be useful if you want
303-- to e.g. convert JSON data to YAML data, without knowing what the
304-- contents of the original JSON data was. The 'Value' type, which is
305-- an instance of 'FromJSON', is used to represent an arbitrary JSON
306-- AST (abstract syntax tree). Example usage:
308-- > >>> decode "{\"foo\": 123}" :: Maybe Value
309-- > Just (Object (fromList [("foo",Number 123)]))
311-- > >>> decode "{\"foo\": [\"abc\",\"def\"]}" :: Maybe Value
312-- > Just (Object (fromList [("foo",Array (fromList [String "abc",String "def"]))]))
314-- Once you have a 'Value' you can write functions to traverse it and
315-- make arbitrary transformations.
319-- We can decode to any instance of 'FromJSON':
321-- > λ> decode "[1,2,3]" :: Maybe [Int]
324-- Alternatively, there are instances for standard data types, so you
325-- can use them directly. For example, use the 'Data.Map.Map' type to
326-- get a map of 'Int's.
328-- > λ> import Data.Map
329-- > λ> decode "{\"foo\":1,\"bar\":2}" :: Maybe (Map String Int)
330-- > Just (fromList [("bar",2),("foo",1)])
334-- The above approach with maps of course will not work for mixed-type
335-- objects that don't follow a strict schema, but there are a couple
336-- of approaches available for these.
338-- The 'Object' type contains JSON objects:
340-- > λ> decode "{\"name\":\"Dave\",\"age\":2}" :: Maybe Object
341-- > Just (fromList) [("name",String "Dave"),("age",Number 2)]
343-- You can extract values from it with a parser using 'parse',
344-- 'parseEither' or, in this example, 'parseMaybe':
346-- > λ> do result <- decode "{\"name\":\"Dave\",\"age\":2}"
347-- > flip parseMaybe result $ \obj -> do
348-- > age <- obj .: "age"
349-- > name <- obj .: "name"
350-- > return (name ++ ": " ++ show (age*2))
354-- Considering that any type that implements 'FromJSON' can be used
355-- here, this is quite a powerful way to parse JSON. See the
356-- documentation in 'FromJSON' for how to implement this class for
357-- your own data types.
359-- The downside is that you have to write the parser yourself; the
360-- upside is that you have complete control over the way the JSON is
363-- $encoding_and_decoding
365-- Decoding is a two-step process.
367-- * When decoding a value, the process is reversed: the bytes are
368-- converted to a 'Value', then the 'FromJSON' class is used to
369-- convert to the desired type.
371-- There are two ways to encode a value.
373-- * Convert to a 'Value' using 'toJSON', then possibly further
374-- encode. This was the only method available in aeson 0.9 and
377-- * Directly encode (to what will become a 'L.ByteString') using
378-- 'toEncoding'. This is much more efficient (about 3x faster, and
379-- less memory intensive besides), but is only available in aeson
382-- For convenience, the 'encode' and 'decode' functions combine both
387-- In older versions of this library, encoding a Haskell value
388-- involved converting to an intermediate 'Value', then encoding that.
390-- A \"direct\" encoder converts straight from a source Haskell value
391-- to a 'BL.ByteString' without constructing an intermediate 'Value'.
392-- This approach is faster than 'toJSON', and allocates less memory.
393-- The 'toEncoding' method makes it possible to implement direct
394-- encoding with low memory overhead.
396-- To complicate matters, the default implementation of 'toEncoding'
397-- uses 'toJSON'. Why? The 'toEncoding' method was added to this
398-- library much more recently than 'toJSON'. Using 'toJSON' ensures
399-- that packages written against older versions of this library will
400-- compile and produce correct output, but they will not see any
401-- speedup from direct encoding.
403-- To write a minimal implementation of direct encoding, your type
404-- must implement GHC's 'Generic' class, and your code should look
408-- 'toEncoding' = 'genericToEncoding' 'defaultOptions'
411-- What if you have more elaborate encoding needs? For example,
412-- perhaps you need to change the names of object keys, omit parts of
415-- To encode to a JSON \"object\", use the 'pairs' function.
418-- 'toEncoding' (Person name age) =
419-- 'pairs' (\"name\" '.=' 'name' '<>' \"age\" '.=' age)
422-- Any container type that implements 'Foldable' can be encoded to a
423-- JSON \"array\" using 'foldable'.
425-- > > import Data.Sequence as Seq
426-- > > encode (Seq.fromList [1,2,3])
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list