I'm trying to parse embedded JSON of the form
{
"foo":"bar",
"baz":"\{\"somekey\":\"someval\"\}"
}
with Aeson in Haskell. Here are my types:
data BaseType = BaseType { foo :: String, baz :: EmbeddedType } deriving(Show)
instance FromJSON BaseType where
parseJSON = withObject "BaseType" $ \o -> do
foo <- o .: "foo"
baz <- o .: "baz"
return $ BaseType { foo=foo, baz=baz }
data EmbeddedType = EmbeddedType { somekey :: String }
instance FromJSON EmbeddedType where
parseJSON = withObject "EmbeddedType" $ \o -> do
somekey <- o .: "somekey"
return $ EmbeddedType {somekey=somekey}
Obviously, the FromJSON
instance for BaseType
doesn't work, since it sees it as a Value String
instead of as more JSON for it to parse. I tried to find a way to use decodeEither
in my FromJSON BaseType
instance, but that required that I do some black magic to convert from String
to ByteString
, and I feel like there must be a neater way, possibly related to withEmbeddedJSON
.
How can I make this work correctly?
I guess it would be something like this (untested):
instance FromJSON BaseType where
parseJSON = withObject "BaseType" $ \o -> do
foo <- o .: "foo"
bazText <- o .: "baz"
baz <- withEmbeddedJSON "EmbeddedType" parseJSON (String bazText)
return $ BaseType { foo=foo, baz=baz }
Or you could consider moving the call to withEmbeddedJSON
into the EmbeddedType
instance; then o .: "baz"
should Just Work in the BaseType
instance, at the cost of no longer having a handle onto a parser that just does EmbeddedType
parsing without de-stringifying:
instance FromJSON BaseType where
parseJSON = withObject "BaseType" $ \o -> do
foo <- o .: "foo"
baz <- o .: "baz"
return $ BaseType { foo=foo, baz=baz }
instance FromJSON EmbeddedType where
parseJSON = withEmbeddedJSON "EmbeddedType" . withObject "EmbeddedType" $ \o -> do
somekey <- o .: "somekey"
return $ EmbeddedType {somekey=somekey}