JSON
Data.Aeson
, from the aeson
package, is a library for encoding/decoding Haskell values to/from JSON.
One of the main appeals of the library is that a JSON string, which is untyped, can be automatically parsed into a typed Haskell value.
Encoding to JSON¶
> encode [4, 3]
"[4,3]"
> encode [(4, 3)]
"[[4,3]]"
> encode ['a', 'b']
"\"ab\""
> encode 4
"4"
> encode (M.fromList [("John", 12), ("Jane", 13)]) -- (1)!
"{\"Jane\":13,\"John\":12}"
-- an example with a custom datatype
> :set -XDeriveGeneric -XDeriveAnyClass -- (2)!
> data Piece = Bishop | Knight deriving (Generic, ToJSON)
> encode [Bishop, Knight]
"[\"Bishop\",\"Knight\"]"
- A dictionary.
- These are needed to derive
Generic
andToJSON
respectively.
Decoding from JSON¶
:set -XOverloadedStrings -- (1)!
import Data.Aeson
> eitherDecode "[1,2,3]" :: Either String [Int] -- (2)!
Right [1,2,3]
> eitherDecode "[1,2," :: Either String [Int]
Left "Error in $: not enough input. Expecting json list value" -- (3)!
> eitherDecode "[1,2,3]" :: Either String (Int, Int, Int)
Right (1,2,3) -- (4)!
> eitherDecode "[1,2,3]" :: Either String (Int, Int, Double)
Right (1,2,3.0) -- (5)!
> str = "{ \"name\": \"Joe\", \"age\": \"12\" }"
> eitherDecode str :: Either String (Map String String)
Right (fromList [("age","12"),("name","Joe")])
> eitherDecode str :: Either String Value -- (6)!
Right (Object (fromList [("age",String "12"),("name",String "Joe")]))
-
aeson
uses theByteString
representation of text. See this gotcha -
eitherDecode
attempts to decode a JSON bytestring into a Haskell datatype. -
If it fails, it returns an error message.
-
The result of the decoding depends on the type you specify. Both [Int] and (Int, Int, Int) work for decoding "[1,2,3]".
-
As does
(Int, Int, Double)
. -
Value
is a type provided byaeson
which corresponds to any JSON, but as a Haskell value.
The user can determine the Haskell type that the JSON should be decoded into. Types which are possible must implement the FromJSON
typeclass, which is automatically implemented for many types, and can be derived automatically for custom types:
> :set -XDeriveGeneric -XDeriveAnyClass -XOverloadedStrings -- (1)!
> import GHC.Generics -- (2)!
> str = "{ \"name\": \"Joe\", \"age\": 12 }" -- (3)!
> data Person = Person { name :: Text, age :: Int}
deriving (Generic, Show, FromJSON)
> eitherDecode str :: Either String Person
Right (Person {name = "Joe", age = 12})
- These extensions are needed.
- A library used for automatic derivations, among other things.
- The JSON bytestring.
With lenses¶
Lenses are an extremely useful tool for working with JSON in Haskell. See here
Created: January 12, 2023