How to correctly output error when parsing JSON using Data.Aeson

My type and corresponding implementation of FromJSON as below.

nonEmptyturns a Listinto Maybe NonEmpty, and I'm trying to correctly deal with the case when it is Listreally empty, and I have to interrupt the parsing. This parsing is actually done internally parseJsonBody, which means I don't want error "foo"to exit it, but I want to return mzero(or something else will do the trick mzero- the only thing I've come across so far), so the handler correctly returns 400 instead of crashing with 500.

The approach compiled below, but as far as I can tell, is pretty much equal to erroror some other form of exception throwing inside parseJSON. If I return mzerohowever (for example, using <*> mzeroinstead of this line), this is not as good as intended.

import qualified Data.List.NonEmpty as NE
data GSAnswer = GSAnswer { gsAnswerQuestionId :: Int
                         , gsAnswerResponses :: NE.NonEmpty GSResponse
                         } deriving (Show, Eq)


instance FromJSON GSAnswer where
  parseJSON (Object o) =
    GSAnswer <$> o .: "question-id"
             -- how do I return mzero here based on NE.nonEmpty?
             -- this will throw an exception right now on an empty list
             <*> fmap (fromMaybe (fail "foo") . NE.nonEmpty) (o .: "responses")
  parseJSON _ = mzero

One option would be to somehow match the templates with the result fmap NE.nonEmpty (o .: "responses"), but I can’t figure out which template will be there: doesn't it look like Parser has any constructors?

+4
source share
1 answer

Essentially, you need a transformer Parser [a] -> Parser NE.NonEmptythat is relatively simple:

-- toNonEmptyP :: Parser [a] -> Parser NE.NonEmtpy
toNonEmptyP p = fmap NE.nonEmpty p >>= maybe mzero return

NE.nonEmpty , Parser (Maybe NE.NonEmpty). Maybe Maybe mzero, Nothing, return . FromJSON

instance FromJSON GSAnswer where
  parseJSON (Object o) =
    GSAnswer <$> o .: "question-id"
             <*> toNonEmptyP (o .: "responses")
  parseJSON _ = mzero

fail msg mzero, , fail :: String -> Parser a .

+3

All Articles