user1198582
user1198582

Reputation:

JSON parsing befuddlement

I'm working on the I/O aspect of my json server, and there's a method I just can't get right. First, I'll give the error, then the code and datatypes involved and some commentary about the problem afterwards.

("X-Response-Body-Start","<!DOCTYPE html>\n<html><head><title>Invalid Arguments</title></head><body><h1>Invalid Arguments</h1><ul><li>when expecting a unit constructor (U1), encountered String instead</li></ul></body></html>")

Expecting unit contructor?

Okay here's some relevant code. Let's see if we can see where I go wrong from Datatypes.hs

data JobID = JobID Project Int deriving Generic

data Project = BNAP deriving (Show,Generic) -- one day to be an ADT

instance ToJSON Project where
   toJSON = toJSON . show

instance FromJSON Project

instance FromJSON JobID
instance ToJSON JobID

The test code

testReadR :: IO Value
testReadR = do
   req <- parseUrl readURI
   manager <- newManager def
   pBody <- runResourceT $ do
               reqBody <- readObject
               liftIO $ print reqBody
               Response _ _ _ body <- http (buildReq req reqBody) manager
               pBody <- body $$+- sinkParser json
               return pBody  -- (return wraps it up)
   closeManager manager
   return pBody

buildReq :: forall a (m :: * -> *) (t :: * -> *).
            ToJSON a =>
            Request t -> a -> Request m
buildReq req reqBody =
   let reqBodyBS = Data.Aeson.encode reqBody
       rHeaders = [(hContentType,pack "application/json")]
   in  req {method = fromString "POST"
           , requestBody = RequestBodyLBS reqBodyBS
           ,requestHeaders=rHeaders
           }
readObject :: ResourceT IO Value
readObject = do -- I took a bunch out because I thought simplifiying would help me
                -- solve this
   return $ Data.Aeson.toJSON $ JobID BNAP 306

The Handler

postReadR :: Handler RepJson
postReadR = do
   conf <- parseJsonBody_ :: Handler JobID        
   liftIO $ print conf
   testJ <- jsonToRepJson $ toJSON $ JobID BNAP 305
   jValue <- jsonToRepJson conf -- to be replaced with 
                                -- Either ErrorReport Response
                                -- (or something like that)
   return jValue

when I change the line to conf <- parseJsonBody_ :: Handler Value

print conf yields Array (fromList [String "BNAP",Number 306])

So it seems the problem lies with String "BNAP" but I don't know why. Any ideas on how I can suss this out? Is there an obvious answer I'm not seeing?

Update : I have a new error. I'm sure I borked the FromJSON instance.

test: ResponseTimeout

instance FromJSON Project where
   parseJSON (String p) = parseJSON $ toJSON p
   parseJSON _ = mzero

The challenge here was that Project is a unary type. None of the examples I studied seemed to address that. But I know p is a Text, and toJSON can make a Value out of that, and parseJSON makes a Parser out of the Value. So it's all good right? Well, I still get the above error which is not informative at all. Any ideas?

Upvotes: 0

Views: 279

Answers (1)

Daniel Fischer
Daniel Fischer

Reputation: 183978

instance ToJSON Project where
   toJSON = toJSON . show

instance FromJSON Project

The instances don't work together. The generic FromJSON instance expects the generic unit constructor U1, but the ToJSON instance produces a String "BNAP".

If you have a hand-written ToJSON instance, you also need a hand-written FromJSON instance.


instance FromJSON Project where
   parseJSON (String p) = parseJSON $ toJSON p
   parseJSON _ = mzero

p is a Text, and we have

instance ToJSON Text where
    toJSON = String

so the above instance for Project loops, since it expands parseJSON (String p) = parseJSON (String p).

For the type as it stands now,

instance FromJSON Project where
    parseJSON (String "BNAP") = return BNAP
    parseJSON _               = mzero

should work if you have OverloadedStrings enabled, if not,

instance FromJSON Project where
    parseJSON (String p)
        | p == pack "BNAP" = return BNAP
    parseJSON _            = mzero

Upvotes: 1

Related Questions