Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Omitting Nothing/null fields in Haskell's Aeson

I have a type

{-# LANGUAGE DeriveGeneric   #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE MultiWayIf      #-}

import GHC.Generics
import Data.Aeson.TH
import Data.Aeson.Types

data MyJSONObject = MyJSONObject
  { name    :: String
  , ptype   :: Maybe String
  , pid     :: Maybe String
  , subject :: Maybe String
  , message :: Maybe String
  } deriving (Show, Generic)

with a great many more Maybe String fields. My FromJSON and ToJSON are provided by the TemplateHaskell function

$(deriveJSON defaultOptions
  {
    omitNothingFields  = True
  , fieldLabelModifier = \f -> if
      | f == "ptype" -> "type" -- reserved keyword
      | f == "pid"   -> "id"   -- Prelude function name
      | otherwise    -> f
  } ''MyJSONObject)

Ultimately, the output of the program is a JSON document intended to be consumed by an application that does not permit some fields to have null values, even if it does allow these fields to not exist. In other words, it's perfectly fine for subject to not be present in the JSON document, but if it does exist, its value cannot be null. My expectation was that omitNothingFields would handle this requirement, but this does not appear to be the case: the decoded JSON still has Nothing values for fields that are not present, and the encoded JSON has null values for those fields. The former case is fine; the latter case is not, hence the question.

Am I misusing, or misunderstanding the purpose of, omitNothingFields? How can I ignore fields with Nothing/null values?

like image 254
user4601931 Avatar asked Nov 03 '17 16:11

user4601931


1 Answers

Works for me. Try using Generics deriving instead of TH. Maybe that's doing it.

*Main Data.Aeson> decode "{\"name\":\"str\"}" :: Maybe MyJSONObject
Just (MyJSONObject {name = "str", ptype = Nothing, pid = Nothing, subject = Nothing, message = Nothing})
*Main Data.Aeson> encode (MyJSONObject "str" Nothing Nothing Nothing Nothing)
"{\"name\":\"str\"}"

The full code is

{-# LANGUAGE DeriveGeneric   #-}
import GHC.Generics
import Data.Aeson
import Data.Aeson.Types

data MyJSONObject = MyJSONObject
  { name    :: String
  , ptype   :: Maybe String
  , pid     :: Maybe String
  , subject :: Maybe String
  , message :: Maybe String
  } deriving (Show, Generic)

instance ToJSON MyJSONObject where
  toJSON = genericToJSON defaultOptions
    { omitNothingFields = True }

instance FromJSON MyJSONObject where
  parseJSON = genericParseJSON defaultOptions
    { omitNothingFields = True }

Using GHC 8.2.1, aeson-1.1.2.0.

like image 117
Mateusz Kowalczyk Avatar answered Sep 27 '22 22:09

Mateusz Kowalczyk