3

I'm creating an object as JSON using aeson. How to add a field "email" to the object?

> import Data.Aeson
> let alice = object ["name" .= "Alice", "age" .= 20]

I tried to use <> but didn't work

> import Data.Monoid
> alice <> object ["email" .= "alice@example.org"]

<interactive>:12:1: error:
    • No instance for (Monoid Value) arising from a use of ‘<>’
    • In the expression:
        alice <> object ["email" .= "alice@example.org"]
      In an equation for ‘it’:
          it = alice <> object ["email" .= "alice@example.org"]
Leo Zhang
  • 3,040
  • 3
  • 24
  • 38
  • 1
    The reason `<>` doesn't work is because there is no obvious way to combine two arbitrary JSON values. For something known to be an object, or known to be an array, it's simple to combine. But because `alice :: Value`, you have lost the information that it's an object, and there's no way to define `(<>) :: Value -> Value -> Value`. – amalloy Jul 18 '18 at 22:55

1 Answers1

3

In my previous project, I used to do something like this:

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

addJsonKey :: Text -> Value -> Value -> Value
addJsonKey key val (Object xs) = Object $ HM.insert key val xs
addJsonKey _ _ xs = xs

And then on ghci:

λ> :set -XOverloadedStrings
λ> let alice = object ["name" .= "Alice", "age" .= 20]
λ> addJsonKey "email" (String "sibi@psibi.in") alice

The key on making it work is understanding how the type Value is defined: https://www.stackage.org/haddock/lts-12.1/aeson-1.3.1.1/Data-Aeson.html#t:Value

Sibi
  • 47,472
  • 16
  • 95
  • 163