on master help sign in
Improve introductionary documentation

De-emphasize working directly with the Value type as this is not the common (or recommended) way to use the library, but still include documentation on how to use it when it's called for. Since the documentation on using generics is documented in the FromJSON and ToJSON classes, refer to that documentation instead of only documenting one method (which is not the preferred method anymore with default signatures I believe).

commitd671309c4f0ca28fed183237196cf42631a5e4b8 authorJohan Tibell <johan.tibell@gmail.com> dateFri 30 Nov 2012, 11:12 (14 years ago) parenta59a3e4
1 file changed+122−126
Data/Aeson.hs+122−126
Data/Aeson.hs+122−126
@@ -11,136 +11,20 @@
1111--
1212-- (A note on naming: in Greek mythology, Aeson was the father of Jason.)
1313--
14−-- /DECODING TO AN ADT ('VALUE')/
15−--
16−-- To parse JSON into something useful, everything goes through the
17−-- 'decode' function, which is polymorphic on the 'FromJSON'
18−-- class. For representing arbitrary JSON AST there is a 'Value' type,
19−-- which is an instance of 'FromJSON'. For example:
20−--
21−-- > λ> decode "{\"foo\":123}" :: Maybe Value
22−-- > Just (Object (fromList [("foo",Number 123)]))
23−-- > λ> decode "{\"foo\":[\"abc\",\"def\"]}" :: Maybe Value
24−-- > Just (Object (fromList [("foo",Array (fromList [String "abc",String "def"]))]))
25−--
26−-- To run these examples, you need to enable @OverloadedStrings@ (in
27−-- GHCi you can write @:set -XOverloadedStrings@) so that you can use
28−-- string literals for non-'String' types. We're using (the lazy
29−-- version of) 'Data.ByteString.Lazy.ByteString', which requires at
30−-- least version 0.9.0.4 of the bytestring package to provide the
31−-- 'Data.String.IsString' instance. You probably have something newer
32−-- than this installed.
33−--
34−-- /DECODING TO HASKELL TYPES/
35−--
36−-- Any instance of 'FromJSON' can be specified (but see the PITFALLS section):
37−--
38−-- > λ> decode "[1,2,3]" :: Maybe [Int]
39−-- > Just [1,2,3]
40−--
41−-- Alternatively, there are instances for standard data types, so you
42−-- can use them directly. For example, use the 'Data.Map.Map' type to
43−-- get a map of 'Int's.
44−--
45−-- > λ> :m + Data.Map
46−-- > λ> decode "{\"foo\":1,\"bar\":2}" :: Maybe (Map String Int)
47−-- > Just (fromList [("bar",2),("foo",1)])
48−--
49−-- /DECODING A HETEROGENOUS OBJECT/
50−--
51−-- The above approach with maps of course will not work for
52−-- heterogenous objects, so there are a couple of approaches available
53−-- to you.
54−--
55−-- The 'Object' type contains JSON objects:
56−--
57−-- > λ> decode "{\"name\":\"Dave\",\"age\":2}" :: Maybe Object
58−-- > Just (fromList) [("name",String "Dave"),("age",Number 2)]
59−--
60−-- And you extract values from it with a parser using 'parse',
61−-- 'parseEither' or, in this example, 'parseMaybe':
62−--
63−-- > λ> do result <- decode "{\"name\":\"Dave\",\"age\":2}"
64−-- > flip parseMaybe result $ \obj -> do
65−-- > age <- obj .: "age"
66−-- > name <- obj .: "name"
67−-- > return (name ++ ": " ++ show (age*2))
68−-- >
69−-- > Just "Dave: 4"
70−--
71−-- Considering that any type that implements 'FromJSON' can be used
72−-- here, this is quite a powerful way to parse JSON. See the
73−-- documentation in 'FromJSON' for how to implement this class for
74−-- your own data types.
75−--
76−-- The downside is that you have to write the parser yourself, the
77−-- upside is that you have complete control over the way the JSON is
78−-- parsed.
79−--
80−-- /DECODING CUSTOM DATA TYPES GENERICALLY WITH TYPEABLE/
81−--
82−-- If you don't want such control and would prefer the JSON be parsed
83−-- to your own data types automatically according to some reasonably
84−-- sensible isomorphic implementation, you can use the generic parser
85−-- based on 'Data.Typeable.Typeable' and 'Data.Data.Data'. Switch to
86−-- the 'Data.Aeson.Generic' module, and you can do the following:
87−--
88−-- > λ> decode "[1]" :: Maybe [Int]
89−-- > Just [1]
90−-- > λ> :m + Data.Typeable Data.Data
91−-- > λ> :set -XDeriveDataTypeable
92−-- > λ> data Person = Person { personName :: String, personAge :: Int } deriving (Data,Typeable,Show)
93−-- > λ> encode Person { personName = "Chris", personAge = 123 }
94−-- > "{\"personAge\":123,\"personName\":\"Chris\"}"
95−-- > λ> decode "{\"personAge\":123,\"personName\":\"Chris\"}" :: Maybe Person
96−-- > Just (Person {
97−-- > personName = "Chris", personAge = 123
98−-- > })
99−--
100−-- Be aware that the encoding might not be what you expect:
101−--
102−-- > λ> data Foo = Foo Int Int deriving (Data,Typeable,Show)
103−-- > λ> encode (Foo 1 2)
104−-- > "[1,2]"
105−--
106−-- So it's better to treat the 'Data.Aeson.Generic.decode' and
107−-- 'Data.Aeson.Generic.encode' functions as an isomorphism, but do not
108−-- rely or care about the actual intermediate representation.
109−--
110−-- /PITFALLS/
111−--
112−-- Note that the JSON standard only allows arrays or objects of things
113−-- at the top-level, so calling decode on a simple type will not work:
114−--
115−-- > λ> decode "1" :: Maybe Int
116−-- > Nothing
117−-- > λ> decode "1" :: Maybe String
118−-- > Nothing
119−--
120−-- So stick to objects (e.g. maps in Haskell) or arrays (lists in Haskell):
121−--
122−-- > λ> decode "[1,2,3]" :: Maybe [Int]
123−-- > Just [1,2,3]
124−--
125−-- Likewise, for encoding to JSON you can encode anything that's an
126−-- instance of 'ToJSON', which does include simple types. So beware
127−-- that this aspect of the API is not isomorphic:
128−--
129−-- > λ> encode [1,2,3]
130−-- > "[1,2,3]"
131−-- > λ> decode (encode [1]) :: Maybe [Int]
132−-- > Just [1]
133−-- > λ> encode 1
134−-- > "1"
135−-- > λ> decode (encode (1 :: Int)) :: Maybe Int
136−-- > Nothing
137−--
138−-- Alternatively see 'Data.Aeson.Parser.value' to parse non-toplevel
139−-- JSON values.
14014
14115module Data.Aeson
14216 (
17+ -- * Usage example
18+ -- $usage-example
19+
20+ -- * Working directly with the JSON AST
21+ -- $json-ast
22+
23+ -- * Pitfalls
24+ -- $pitfalls
25+
14326 -- * Encoding and decoding
27+ -- $encoding-and-decoding
14428 decode
14529 , decode'
14630 , eitherDecode
@@ -208,3 +92,115 @@ eitherDecode = eitherDecodeWith json fromJSON
20892eitherDecode' :: (FromJSON a) => L.ByteString -> Either String a
20993eitherDecode' = eitherDecodeWith json' fromJSON
21094{-# INLINE eitherDecode' #-}
95+
96+-- $usage-example
97+--
98+-- The most common way to use the library is to define a data type,
99+-- corresponding to some JSON data you want to work with, and then
100+-- write either a 'FromJSON' instance, a to 'ToJSON' instance, or both
101+-- for that type. For example, given this JSON data:
102+--
103+-- > { "name": "Joe", "age": 12 }
104+--
105+-- we create a matching data type:
106+--
107+-- > data Person = Person
108+-- > { name :: Text
109+-- > , age :: Int
110+-- > } deriving Show
111+--
112+-- To decode data, we need to define a 'FromJSON' instance:
113+--
114+-- > {-# LANGUAGE OverloadedStrings #-}
115+-- >
116+-- > instance FromJSON Coord where
117+-- > parseJSON (Object v) = Person <$>
118+-- > v .: "name" <*>
119+-- > v .: "age"
120+-- > -- A non-Object value is of the wrong type, so fail.
121+-- > parseJSON _ = mzero
122+--
123+-- We can now parse the JSON data like so:
124+--
125+-- > >>> decode "{\"name\":\"Joe\",\"age\":12}" :: Maybe Person
126+-- > Just (Person {name = "Joe", age = 12})
127+--
128+-- The explicit type signature can often be omitted as the compiler
129+-- can deduce the type using type inference.
130+--
131+-- To encode data, we need to define a 'ToJSON' instance:
132+--
133+-- > instance ToJSON Person where
134+-- > toJSON (Person name age) = object ["name" .= name, "age" .= age]
135+--
136+-- We can now encode a value like so:
137+--
138+-- > >>> encode (Person {name = "Joe", age = 12})
139+-- > "{\"name\":\"Joe\",\"age\":12}"
140+--
141+-- There are predefined 'FromJSON' and 'ToJSON' instances for many
142+-- types. Here's an example using lists and 'Int's:
143+--
144+-- > >>> decode "[1,2,3]" :: Maybe [Int]
145+-- > Just [1,2,3]
146+--
147+-- And here's an example using the 'Data.Map.Map' type to get a map of
148+-- 'Int's.
149+--
150+-- > >>> decode "{\"foo\":1,\"bar\":2}" :: Maybe (Map String Int)
151+-- > Just (fromList [("bar",2),("foo",1)])
152+--
153+-- See the documentation of 'FromJSON' and 'ToJSON' for some examples
154+-- how you can automatically dervice instances in some circumstances.
155+
156+
157+-- $json-ast
158+--
159+-- Sometimes you want to work with JSON data directly, without first
160+-- converting it to a custom data type. This can be useful if you want
161+-- to e.g. convert JSON data to YAML data, without knowing what the
162+-- contents of the original JSON data was. The 'Value' type, which is
163+-- an instance of 'FromJSON', is used to represent an arbitrary JSON
164+-- AST. Example usage:
165+--
166+-- > >>> decode "{\"foo\": 123}" :: Maybe Value
167+-- > Just (Object (fromList [("foo",Number 123)]))
168+-- > >>> decode "{\"foo\": [\"abc\",\"def\"]}" :: Maybe Value
169+-- > Just (Object (fromList [("foo",Array (fromList [String "abc",String "def"]))]))
170+--
171+-- Once you have a 'Value' you can write recursive functions to
172+-- traverse it and make arbitrary transformations.
173+
174+-- $pitfalls
175+--
176+-- Note that the JSON standard only allows arrays or objects of things
177+-- at the top-level, so calling decode on a simple type will not work:
178+--
179+-- > >>> decode "1" :: Maybe Int
180+-- > Nothing
181+-- > >>> decode "1" :: Maybe String
182+-- > Nothing
183+--
184+-- Likewise, for encoding to JSON you can encode anything that's an
185+-- instance of 'ToJSON', which does include simple types. So beware
186+-- that this aspect of the API is not isomorphic:
187+--
188+-- > >>> encode [1,2,3]
189+-- > "[1,2,3]"
190+-- > >>> decode (encode [1]) :: Maybe [Int]
191+-- > Just [1]
192+-- > >>> encode 1
193+-- > "1"
194+-- > >>> decode (encode (1 :: Int)) :: Maybe Int
195+-- > Nothing
196+--
197+-- Alternatively see 'Data.Aeson.Parser.value' to parse non-toplevel
198+-- JSON values.
199+
200+-- $encoding-and-decoding
201+--
202+-- Encoding and decoding is a two step process. To encode a value, it
203+-- is first converted to a generic representation, using 'ToJSON'. The
204+-- generic representation is then encoded as JSON data. To decode a
205+-- value the process is reversed and 'FromJSON' is used instead. Both
206+-- these steps are combined in the 'encode' and 'decode' functions.