Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Data.Aeson encoding optional keys

I have the following problem, I have a JSON format with optional keys that I need to generate from my haskell code.

Lets make an example

{-# LANGUAGE DeriveGeneric #-}

import GHC.Generics
import Data.Aeson

data Person = {
    name :: String,
    shoeSize :: Maybe Int,
    favoriteColor :: Maybe String,
    favoriteFood :: Maybe StringC
} deriving (show, eq, generic)

instance ToJSON Person -- Generic instance

now, if I try encoding a Person without a shoesize I still get a key "shoeSize" set to null, what is the Aeson way of making keys optional in encoding

edit, example of an encode

encode $ Person "windwarrior" Nothing "green" Nothing

should result in

{"name":"windwarrior", "favoriteColor":"green"}
like image 310
windwarrior Avatar asked Dec 26 '22 18:12

windwarrior


2 Answers

Use TemplateHaskell to derive the ToJSON instance instead of Generic. The TH functions optionally take an Options which has the omitNothingFields option.

like image 149
J. Abrahamson Avatar answered Jan 06 '23 12:01

J. Abrahamson


There is the Options datatype with an omitNothingFields field for Generics as well so you don't have to use TemplateHaskell, however there's currently (v0.11.2.0) a bug that makes it generate invalid JSON under certain circumstances, e.g. several record fields. It has been fixed but is in master.

You can also handwrite instances if you prefer, for your example:

instance ToJSON Person where
    toJSON (Person name shoeSize favoriteColor favoriteFood) = object fields
      where
        consMay attr = maybe id ((:) . (attr .=))
        conss = consMay "shoeSize" shoeSize
              . consMay "favoriteColor" favoriteColor
              . consMay "favoriteFood" favoriteFood
        fields = conss ["name" .= name]
like image 44
Shou Avatar answered Jan 06 '23 13:01

Shou