I'm trying to write a FromJSON
function for Aeson.
The JSON:
{
"total": 1,
"movies": [
{
"id": "771315522",
"title": "Harry Potter and the Philosophers Stone (Wizard's Collection)",
"posters": {
"thumbnail": "http://content7.flixster.com/movie/11/16/66/11166609_mob.jpg",
"profile": "http://content7.flixster.com/movie/11/16/66/11166609_pro.jpg",
"detailed": "http://content7.flixster.com/movie/11/16/66/11166609_det.jpg",
"original": "http://content7.flixster.com/movie/11/16/66/11166609_ori.jpg"
}
}
]
}
The ADT: data Movie = Movie {id::String, title::String}
My attempt:
instance FromJSON Movie where
parseJSON (Object o) = do
movies <- parseJSON =<< (o .: "movies") :: Parser Array
v <- head $ decode movies
return $ Movie <$>
(v .: "movies" >>= (.: "id") ) <*>
(v .: "movies" >>= (.: "title") )
parseJSON _ = mzero
This gives Couldn't match expected type 'Parser t0' with actual type 'Maybe a0' In the first argument of 'head'
.
As you can see, I'm trying to pick the first of the movies in the Array
, but I wouldn't mind getting a list of Movies either (in case there are several in the Array).
It's usually easiest to match the structure of your ADTs and instances to the structure of your JSON.
Here, I've added a newtype
MovieList
to deal with the outermost object so that the instance forMovie
only has to deal with a single movie. This also gives you multiple movies for free via theFromJSON
instance for lists.If you really want to parse a single
Movie
from a JSON array of movies, you can do something like this:But the safer route would be to parse a
[Movie]
vianewtype
wrapper: