Yunis
Yunis

Reputation: 23

yesod cast "responseBody" to a haskell type

the following code makes an api call in yesod. the question is how do i "cast" the resulting object to a predefined haskell type?

Network.HTTP.Conduit.withManager $ \manager -> do
    response <- http req manager
    resBody <- responseBody response C.$$+- sinkParser json
    liftIO $ putStrLn $ T.pack (show resBody)

example output log

Object (fromList [("val1",Number 1.0),("val2",String "text")])

all the attempts i have made to decode with Aeson or fromJSON are failing.

much appreciated

yunis

Upvotes: 1

Views: 120

Answers (1)

Dan Burton
Dan Burton

Reputation: 53695

Where the value came from doesn't seem to matter. You've got a hold of a piece of data with type Aeson.Value, so you just have to figure out how to succeed in your attempts with fromJSON.

Here's a bit of code adapted from the docs for the FromJSON class

{-# LANGUAGE OverloadedStrings #-}

import qualified Data.Aeson as Aeson
import qualified Data.HashMap.Strict as HashMap

import Data.Aeson ((.:))
import Data.Text (Text)

-- this is the data you already have, which you named resBody
resBody :: Aeson.Value
resBody = Aeson.Object $
  HashMap.fromList
    [ ("val1", Aeson.Number 1.0)
    , ("val2", Aeson.String "text")]

-- Step 1: create a custom Haskell data type to house the data.
-- I named it Coord to match the example code from the link above,
-- but you should probably give it a more meaningful name.
data Coord = Coord { x :: Double, y :: Text }
  deriving (Show)

-- Step 2: write a FromJSON instance for your custom data type.
-- In this case, it is almost identical to the example code in the docs.
instance Aeson.FromJSON Coord where
  parseJSON = Aeson.withObject "Coord" $ \v -> Coord
    <$> v .: "val1"
    <*> v .: "val2"

Giving it a spin in the repl

ghci> -- Here's our data
ghci> resBody
Object (fromList [("val1",Number 1.0),("val2",String "text")])
ghci> -- Next, we decode using fromJSON, annotating the result as our desired type
ghci> Aeson.fromJSON resBody :: Aeson.Result Coord
Success (Coord {x = 1.0, y = "text"})

Upvotes: 2

Related Questions