Catch your JSON null values

Filed under: programming

Took me weeks to figure out decoding JSON data from The Hype Machine into a matching Aeson data type.Turns out I didn’t catch potential null values for the thumbnail images.

So instead, I used the Haskell Maybe type to catch it.

thumb_url :: Maybe String

While I didn’t like how long it took to debug, I love how simple it is to provide the exception case with just 1 word! No need to write tests, just check if it has a value :)

So here’s the way I defined the data structure to read the JSON. I wonder if there’s a more elegant way to read the list of 20 similar items?

data Song = Song {
      mediaid :: String,
      artist :: String,
      title :: String,
      dateposted :: Int,
      siteid :: Int,
      sitename :: String,
      posturl :: String,
      postid :: Int,
      loved_count :: Int,
      posted_count :: Int,
      thumb_url :: Maybe String
      thumb_url_medium :: String,
      thumb_url_large :: String,
      thumb_url_artist :: String,
      time :: Int,
      description :: String,
      itunes_link :: String
}

data Songs a = Songs {
    song0 :: a,
    song1 :: a,
    song2 :: a,
    song3 :: a,
    song4 :: a,
    song5 :: a,
    song6 :: a,
    song7 :: a,
    song8 :: a,
    song9 :: a,
    song10 :: a,
    song11 :: a,
    song12 :: a,
    song13 :: a,
    song14 :: a,
    song15 :: a,
    song16 :: a,
    song17 :: a,
    song18 :: a,
    song19 :: a
} deriving (Eq, Show, Read)

instance (FromJSON a) => FromJSON (Songs a) where
  parseJSON (Object v) = Songs
                          (v .: "0")
                          (v .: "1")
                          (v .: "2")
                          (v .: "3")
                          (v .: "4")
                          (v .: "5")
                          (v .: "6")
                          (v .: "7")
                          (v .: "8")
                          (v .: "9")
                          (v .: "10")
                          (v .: "11")
                          (v .: "12")
                          (v .: "13")
                          (v .: "14")
                          (v .: "15")
                          (v .: "16")
                          (v .: "17")
                          (v .: "18")
                          (v .: "19")
  parseJSON _          = empty
  
  instance FromJSON Song where
  parseJSON (Object v) = Song
                          (v .: "mediaid")
                          (v .: "artist")
                          (v .: "title")
                          (v .: "dateposted")
                          (v .: "siteid")
                          (v .: "sitename")
                          (v .: "posturl")
                          (v .: "postid")
                          (v .: "loved_count")
                          (v .: "posted_count")
                          (v .: "thumb_url")
                          (v .: "thumb_url_medium")
                          (v .: "thumb_url_large")
                          (v .: "thumb_url_artist")
                          (v .: "time")
                          (v .: "description")
                          (v .: "itunes_link")

main :: IO ()
main = do
  input  print "error parsing JSON"
    Just m -> Prelude.putStrLn  show m