Reputation: 1287
When trying to parse some simple JSON using Aeson I get a type error I don't understand. I have the following JSON
jsonString = "[\"a\", [\"b\", \"c\"]]" :: L.ByteString
and I have defined the following imports and code:
import Data.Aeson
import GHC.Generics
import qualified Data.ByteString.Lazy as L
data Ch = Ch {
c1 :: String,
c2 :: (String, String)
} deriving (Show, Generic)
instance FromJSON Ch
When I try to use eitherDecode
on this string with my Ch
type I get an error
*Aeson> eitherDecode jsonString :: Either String Ch
Left "Error in $: expected record (:*:), encountered Array"
Can someone explain me the error and tell me how I should parse this JSON?
An approach that would work is
eitherDecode jsonString :: Either String (String, (String, String))
but I'd rather go to my type directly.
Upvotes: 2
Views: 451
Reputation: 64740
If you already know of a type that parses as intended then perhaps the easiest solution is to just write your instance in terms of that type and translating:
import Data.Aeson
import GHC.Generics
import qualified Data.ByteString.Lazy as L
data Ch = Ch {
c1 :: String,
c2 :: (String, String)
} deriving (Show, Generic)
instance FromJSON Ch where
parseJSON x =
do (a,(b,c)) <- parseJSON x
pure (Ch a (b,c))
And the result is:
*Main> :set -XOverloadedStrings
*Main> eitherDecode "[\"a\", [\"b\", \"c\"]]" :: Either String Ch
Right (Ch {c1 = "a", c2 = ("b","c")})
EDIT:
A more direct use of Aeson's API can be informative or preferred:
instance FromJSON Ch where
parseJSON =
withArray "Ch" $ \arr ->
-- from Data.Aeson.Types
if V.length arr /= 2
-- ^ from Data.Vector
then typeMismatch "Length should be 2" (Array arr)
-- ^ from Data.Aeson.Types
else Ch <$> parseJSON (arr ! 0) <*> parseJSON ( arr ! 1 )
Upvotes: 2