Bob Jansen
Bob Jansen

Reputation: 1287

Parsing list with nested list using Aeson

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

Answers (1)

Thomas M. DuBuisson
Thomas M. DuBuisson

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

Related Questions