on master help sign in
More doc improvements
176fbb3Bryan O'Sullivan
Data/Aeson.hs+72−12
@@ -30,6 +30,9 @@ module Data.Aeson
30
30
31 -- * Encoding and decoding
31 -- * Encoding and decoding
32 -- $encoding_and_decoding
32 -- $encoding_and_decoding
33+
34+ -- ** Direct encoding
35+ -- $encoding
33 decode
36 decode
34 , decode'
37 , decode'
35 , eitherDecode
38 , eitherDecode
@@ -54,12 +57,13 @@ module Data.Aeson
54 , fromJSON
57 , fromJSON
55 , ToJSON(..)
58 , ToJSON(..)
56 , KeyValue(..)
59 , KeyValue(..)
57− -- ** Generic JSON classes
60+ -- ** Generic JSON classes and options
58 , GFromJSON(..)
61 , GFromJSON(..)
59 , GToJSON(..)
62 , GToJSON(..)
60 , genericToJSON
63 , genericToJSON
61 , genericToEncoding
64 , genericToEncoding
62 , genericParseJSON
65 , genericParseJSON
66+ , defaultOptions
63
67
64 -- * Inspecting @'Value's@
68 -- * Inspecting @'Value's@
65 , withObject
69 , withObject
@@ -199,8 +203,17 @@ eitherDecodeStrict' =
199-- 'FromJSON' and 'ToJSON' instances for which the compiler will
203-- 'FromJSON' and 'ToJSON' instances for which the compiler will
200-- generate sensible default implementations.
204-- generate sensible default implementations.
201--
205--
206+-- @
202−-- > instance ToJSON Person
207+-- instance 'ToJSON' Person where
208+-- \-- No need to provide a 'toJSON' implementation.
209+--
210+-- \-- For efficiency, we write a simple 'toEncoding' implementation, as
211+-- \-- the default version uses 'toJSON'.
212+-- 'toEncoding' = 'genericToEncoding' 'defaultOptions'
213+--
203−-- > instance FromJSON Person
214+-- instance 'FromJSON' Person
215+-- \-- No need to provide a 'parseJSON' implementation.
216+-- @
204--
217--
205-- We can now encode a value like so:
218-- We can now encode a value like so:
206--
219--
@@ -240,16 +253,19 @@ eitherDecodeStrict' =
240-- > >>> decode "{\"name\":\"Joe\",\"age\":12}" :: Maybe Person
253-- > >>> decode "{\"name\":\"Joe\",\"age\":12}" :: Maybe Person
241-- > Just (Person {name = "Joe", age = 12})
254-- > Just (Person {name = "Joe", age = 12})
242--
255--
243−-- To encode data, we need to define a 'ToJSON' instance:
256+-- To encode data, we need to define a 'ToJSON' instance. Let's begin
257+-- with an instance written entirely by hand.
244--
258--
259+-- @
245−-- > instance ToJSON Person where
260+-- instance ToJSON Person where
246−-- > -- this generates a Value
261+-- \-- this generates a 'Value'
247−-- > toJSON (Person name age) =
262+-- 'toJSON' (Person name age) =
248−-- > object ["name" .= name, "age" .= age]
263+-- 'object' [\"name\" '.=' name, \"age\" '.=' age]
249−-- >
264+--
250−-- > -- this encodes directly to a ByteString Builder
265+-- \-- this encodes directly to a bytestring Builder
251−-- > toEncoding (Person name age) =
266+-- 'toEncoding' (Person name age) =
252−-- > pairs $ "name" .= name <> "age" .= age
267+-- 'pairs' (\"name\" '.=' 'name' '<>' \"age\" '.=' age)
268+-- @
253--
269--
254-- We can now encode a value like so:
270-- We can now encode a value like so:
255--
271--
@@ -363,3 +379,47 @@ eitherDecodeStrict' =
363--
379--
364-- For convenience, the 'encode' and 'decode' functions combine both
380-- For convenience, the 'encode' and 'decode' functions combine both
365-- steps.
381-- steps.
382+
383+-- $encoding
384+--
385+-- In older versions of this library, encoding a Haskell value
386+-- involved converting to an intermediate 'Value', then encoding that.
387+--
388+-- A \"direct\" encoder converts straight from a source Haskell value
389+-- to a 'BL.ByteString' without constructing an intermediate 'Value'.
390+-- This approach is faster than 'toJSON', and allocates less memory.
391+-- The 'toEncoding' method makes it possible to implement direct
392+-- encoding with low memory overhead.
393+--
394+-- To complicate matters, the default implementation of 'toEncoding'
395+-- uses 'toJSON'. Why? The 'toEncoding' method was added to this
396+-- library much more recently than 'toJSON'. Using 'toJSON' ensures
397+-- that packages written against older versions of this library will
398+-- compile and produce correct output, but they will not see any
399+-- speedup from direct encoding.
400+--
401+-- To write a minimal implementation of direct encoding, your type
402+-- must implement GHC's 'Generic' class, and your code should look
403+-- like this:
404+--
405+-- @
406+-- 'toEncoding' = 'genericToEncoding' 'defaultOptions'
407+-- @
408+--
409+-- What if you have more elaborate encoding needs? For example,
410+-- perhaps you need to change the names of object keys, omit parts of
411+-- a value.
412+--
413+-- To encode to a JSON \"object\", use the 'pairs' function.
414+--
415+-- @
416+-- 'toEncoding' (Person name age) =
417+-- 'pairs' (\"name\" '.=' 'name' '<>' \"age\" '.=' age)
418+-- @
419+--
420+-- Any container type that implements 'Foldable' can be encoded to a
421+-- JSON \"array\" using 'foldable'.
422+--
423+-- > > import Data.Sequence as Seq
424+-- > > encode (Seq.fromList [1,2,3])
425+-- > "[1,2,3]"
Data/Aeson/Types/Class.hs+67−31
@@ -1,4 +1,4 @@
1−{-# LANGUAGE DefaultSignatures, FlexibleContexts #-}
1+{-# LANGUAGE CPP, DefaultSignatures, FlexibleContexts #-}
2
2
3-- |
3-- |
4-- Module: Data.Aeson.Types.Class
4-- Module: Data.Aeson.Types.Class
@@ -72,45 +72,60 @@ genericParseJSON opts = fmap to . gParseJSON opts
72--
72--
73-- An example type and instance:
73-- An example type and instance:
74--
74--
75+-- @
76+-- \-- Allow ourselves to write 'Text' literals.
75−-- @{-\# LANGUAGE OverloadedStrings #-}
77+-- {-\# LANGUAGE OverloadedStrings #-}
76--
78--
77-- data Coord = Coord { x :: Double, y :: Double }
79-- data Coord = Coord { x :: Double, y :: Double }
78--
80--
79-- instance ToJSON Coord where
81-- instance ToJSON Coord where
80-- toJSON (Coord x y) = 'object' [\"x\" '.=' x, \"y\" '.=' y]
82-- toJSON (Coord x y) = 'object' [\"x\" '.=' x, \"y\" '.=' y]
81−-- @
82--
83--
83−-- Note the use of the @OverloadedStrings@ language extension which enables
84+-- toEncoding (Coord x y) = 'pairs' (\"x\" '.=' x '<>' \"y\" '.=' y)
84−-- 'Text' values to be written as string literals.
85+-- @
85--
86--
86−-- Instead of manually writing your 'ToJSON' instance, there are three options
87+-- Instead of manually writing your 'ToJSON' instance, there are two options
87-- to do it automatically:
88-- to do it automatically:
88--
89--
89-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
90-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
90-- instance at compile time. The generated instance is optimized for your type
91-- instance at compile time. The generated instance is optimized for your type
91-- so will probably be more efficient than the following two options:
92-- so will probably be more efficient than the following two options:
92--
93--
93−-- * The compiler can provide default generic implementations for 'toJSON' and
94+-- * The compiler can provide a default generic implementation for
94−-- 'toEncoding'.
95+-- 'toJSON'.
95--
96--
96-- To use the second, simply add a @deriving 'Generic'@ clause to your
97-- To use the second, simply add a @deriving 'Generic'@ clause to your
97-- datatype and declare a 'ToJSON' instance for your datatype without giving
98-- datatype and declare a 'ToJSON' instance for your datatype without giving
98-- definitions for 'toJSON' or 'toEncoding'.
99-- definitions for 'toJSON' or 'toEncoding'.
99--
100--
100−-- For example, the previous example can be simplified to just:
101+-- For example, the previous example can be simplified to a more
102+-- minimal instance:
101--
103--
104+-- @
102−-- @{-\# LANGUAGE DeriveGeneric \#-}
105+-- {-\# LANGUAGE DeriveGeneric \#-}
103--
106--
104−-- import GHC.Generics
107+-- import "GHC.Generics"
105--
108--
106−-- data Coord = Coord { x :: Double, y :: Double } deriving Generic
109+-- data Coord = Coord { x :: Double, y :: Double } deriving 'Generic'
107--
110--
108−-- instance ToJSON Coord
111+-- instance ToJSON Coord where
112+-- toEncoding = 'genericToEncoding' 'defaultOptions'
109-- @
113-- @
110--
114--
111−-- Note that, instead of using @DefaultSignatures@, it's also possible
115+-- Why do we provide an implementation for 'toEncoding' here? The
112−-- to parameterize the generic encoding using 'genericToJSON' applied
116+-- 'toEncoding' function is a relatively new addition to this class.
113−-- to your encoding/decoding 'Options':
117+-- To allow users of older versions of this library to upgrade without
118+-- having to edit all of their instances or encounter surprising
119+-- incompatibilities, the default implementation of 'toEncoding' uses
120+-- 'toJSON'. This produces correct results, but since it performs an
121+-- intermediate conversion to a 'Value', it will be less efficient
122+-- than directly emitting an 'Encoding'. Our one-liner definition of
123+-- 'toEncoding' above bypasses the intermediate 'Value'.
124+--
125+-- If @DefaultSignatures@ doesn't give exactly the results you want,
126+-- you can customize the generic encoding with only a tiny amount of
127+-- effort, using 'genericToJSON' and 'genericToEncoding' with your
128+-- preferred 'Options':
114--
129--
115-- @
130-- @
116-- instance ToJSON Coord where
131-- instance ToJSON Coord where
@@ -118,11 +133,31 @@ genericParseJSON opts = fmap to . gParseJSON opts
118-- toEncoding = 'genericToEncoding' 'defaultOptions'
133-- toEncoding = 'genericToEncoding' 'defaultOptions'
119-- @
134-- @
120class ToJSON a where
135class ToJSON a where
136+ -- | Convert a Haskell value to a JSON-friendly intermediate type.
121 toJSON :: a -> Value
137 toJSON :: a -> Value
138+ {-# MINIMAL toJSON #-}
122
139
123 default toJSON :: (Generic a, GToJSON (Rep a)) => a -> Value
140 default toJSON :: (Generic a, GToJSON (Rep a)) => a -> Value
124 toJSON = genericToJSON defaultOptions
141 toJSON = genericToJSON defaultOptions
125
142
143+ -- | Encode a Haskell value as JSON.
144+ --
145+ -- The default implementation of this method creates an
146+ -- intermediate 'Value' using 'toJSON'. This provides
147+ -- source-level compatibility for people upgrading from older
148+ -- versions of this library, but obviously offers no performance
149+ -- advantage.
150+ --
151+ -- To benefit from direct encoding, you /must/ provide an
152+ -- implementation for this method. The easiest way to do so is by
153+ -- having your types implement 'Generic' using the @DeriveGeneric@
154+ -- extension, and then have GHC generate a method body as follows.
155+ --
156+ -- @
157+ -- instance ToJSON Coord where
158+ -- toEncoding = 'genericToEncoding' 'defaultOptions'
159+ -- @
160+
126 toEncoding :: a -> Encoding
161 toEncoding :: a -> Encoding
127 toEncoding = Encoding . E.encodeToBuilder . toJSON
162 toEncoding = Encoding . E.encodeToBuilder . toJSON
128 {-# INLINE toEncoding #-}
163 {-# INLINE toEncoding #-}
@@ -130,6 +165,10 @@ class ToJSON a where
130-- | A type that can be converted from JSON, with the possibility of
165-- | A type that can be converted from JSON, with the possibility of
131-- failure.
166-- failure.
132--
167--
168+-- In many cases, you can get the compiler to generate parsing code
169+-- for you (see below). To begin, let's cover writing an instance by
170+-- hand.
171+--
133-- There are various reasons a conversion could fail. For example, an
172-- There are various reasons a conversion could fail. For example, an
134-- 'Object' could be missing a required key, an 'Array' could be of
173-- 'Object' could be missing a required key, an 'Array' could be of
135-- the wrong size, or a value could be of an incompatible type.
174-- the wrong size, or a value could be of an incompatible type.
@@ -138,7 +177,7 @@ class ToJSON a where
138--
177--
139-- * 'empty' and 'mzero' work, but are terse and uninformative
178-- * 'empty' and 'mzero' work, but are terse and uninformative
140--
179--
141−-- * 'fail' produces a custom error message
180+-- * 'fail' yields a custom error message
142--
181--
143-- * 'typeMismatch' produces an informative message for cases when the
182-- * 'typeMismatch' produces an informative message for cases when the
144-- value encountered is not of the expected type
183-- value encountered is not of the expected type
@@ -146,6 +185,7 @@ class ToJSON a where
146-- An example type and instance:
185-- An example type and instance:
147--
186--
148-- @
187-- @
188+-- \-- Allow ourselves to write 'Text' literals.
149-- {-\# LANGUAGE OverloadedStrings #-}
189-- {-\# LANGUAGE OverloadedStrings #-}
150--
190--
151-- data Coord = Coord { x :: Double, y :: Double }
191-- data Coord = Coord { x :: Double, y :: Double }
@@ -155,15 +195,12 @@ class ToJSON a where
155-- v '.:' \"x\" '<*>'
195-- v '.:' \"x\" '<*>'
156-- v '.:' \"y\"
196-- v '.:' \"y\"
157--
197--
158−-- \-- A non-'Object' value is of the wrong type.
198+-- \-- We do not expect a non-'Object' value here.
159−-- \-- We could use mzero to fail, but typeMismatch
199+-- \-- We could use 'mzero' to fail, but 'typeMismatch'
160-- \-- gives a much more informative error message.
200-- \-- gives a much more informative error message.
161-- parseJSON invalid = 'typeMismatch' \"Coord\" invalid
201-- parseJSON invalid = 'typeMismatch' \"Coord\" invalid
162-- @
202-- @
163--
203--
164−-- Note the use of the @OverloadedStrings@ language extension which enables
165−-- 'Text' values to be written as string literals.
166−--
167-- Instead of manually writing your 'FromJSON' instance, there are two options
204-- Instead of manually writing your 'FromJSON' instance, there are two options
168-- to do it automatically:
205-- to do it automatically:
169--
206--
@@ -183,16 +220,16 @@ class ToJSON a where
183-- @
220-- @
184-- {-\# LANGUAGE DeriveGeneric \#-}
221-- {-\# LANGUAGE DeriveGeneric \#-}
185--
222--
186−-- import GHC.Generics
223+-- import "GHC.Generics"
187--
224--
188−-- data Coord = Coord { x :: Double, y :: Double } deriving Generic
225+-- data Coord = Coord { x :: Double, y :: Double } deriving 'Generic'
189--
226--
190-- instance FromJSON Coord
227-- instance FromJSON Coord
191-- @
228-- @
192--
229--
193−-- Note that, instead of using @DefaultSignatures@, it's also possible
230+-- If @DefaultSignatures@ doesn't give exactly the results you want,
194−-- to parameterize the generic decoding using 'genericParseJSON' applied
231+-- you can customize the generic decoding with only a tiny amount of
195−-- to your encoding/decoding 'Options':
232+-- effort, using 'genericParseJSON' with your preferred 'Options':
196--
233--
197-- @
234-- @
198-- instance FromJSON Coord where
235-- instance FromJSON Coord where
@@ -205,9 +242,9 @@ class FromJSON a where
205 default parseJSON :: (Generic a, GFromJSON (Rep a)) => Value -> Parser a
242 default parseJSON :: (Generic a, GFromJSON (Rep a)) => Value -> Parser a
206 parseJSON = genericParseJSON defaultOptions
243 parseJSON = genericParseJSON defaultOptions
207
244
208−-- | A key-value pair for a JSON object.
245+-- | A key-value pair for encoding a JSON object.
209−class KeyValue t where
246+class KeyValue kv where
210− (.=) :: ToJSON v => Text -> v -> t
247+ (.=) :: ToJSON v => Text -> v -> kv
211 infixr 8 .=
248 infixr 8 .=
212
249
213-- | Fail parsing due to a type mismatch, with a descriptive message.
250-- | Fail parsing due to a type mismatch, with a descriptive message.
@@ -215,7 +252,6 @@ class KeyValue t where
215-- Example usage:
252-- Example usage:
216--
253--
217-- @
254-- @
218−--
219-- instance FromJSON Coord where
255-- instance FromJSON Coord where
220-- parseJSON ('Object' v) = {- type matches, life is good -}
256-- parseJSON ('Object' v) = {- type matches, life is good -}
221-- parseJSON wat = 'typeMismatch' \"Coord\" wat
257-- parseJSON wat = 'typeMismatch' \"Coord\" wat
Data/Aeson/Types/Internal.hs+4−3
@@ -222,7 +222,7 @@ type Failure f r = JSONPath -> String -> f r
222-- | Success continuation.
222-- | Success continuation.
223type Success a f r = a -> f r
223type Success a f r = a -> f r
224
224
225−-- | A continuation-based parser type.
225+-- | A JSON parser.
226newtype Parser a = Parser {
226newtype Parser a = Parser {
227 runParser :: forall f r.
227 runParser :: forall f r.
228 JSONPath
228 JSONPath
@@ -325,7 +325,7 @@ instance Monoid Series where
325
325
326-- | A newtype wrapper for 'UTCTime' that uses the same non-standard
326-- | A newtype wrapper for 'UTCTime' that uses the same non-standard
327-- serialization format as Microsoft .NET, whose
327-- serialization format as Microsoft .NET, whose
328−-- <https://msdn.microsoft.com/en-us/library/system.datetime(v=vs.110).aspx @System.DateTime@>
328+-- <https://msdn.microsoft.com/en-us/library/system.datetime(v=vs.110).aspx System.DateTime>
329-- type is by default serialized to JSON as in the following example:
329-- type is by default serialized to JSON as in the following example:
330--
330--
331-- > /Date(1302547608878)/
331-- > /Date(1302547608878)/
@@ -390,7 +390,8 @@ parseMaybe :: (a -> Parser b) -> a -> Maybe b
390parseMaybe m v = runParser (m v) [] (\_ _ -> Nothing) Just
390parseMaybe m v = runParser (m v) [] (\_ _ -> Nothing) Just
391{-# INLINE parseMaybe #-}
391{-# INLINE parseMaybe #-}
392
392
393−-- | Run a 'Parser' with an 'Either' result type.
393+-- | Run a 'Parser' with an 'Either' result type. If the parse fails,
394+-- the 'Left' payload will contain an error message.
394parseEither :: (a -> Parser b) -> a -> Either String b
395parseEither :: (a -> Parser b) -> a -> Either String b
395parseEither m v = runParser (m v) [] onError Right
396parseEither m v = runParser (m v) [] onError Right
396 where onError path msg = Left (formatError path msg)
397 where onError path msg = Left (formatError path msg)