How can I encode None to missing json field using zio-json instead of null?

855 Views Asked by At

Let's say I have a case class with the optional field nickName and codec like this:

final case class Person(name: String, nickName: Option[String])

object Person {
  implicit val personCodec: JsonCodec[Person] = DeriveJsonCodec.gen
}

I want to encode it using zio-json (v1.5.0) and have this as result:

{"name":"SomeName"}

And this is my test for it:

encoder.encodeJson(Person("SomeName", None), None).toString shouldBe """{"name":"SomeName"}""".stripMargin

Looks like the zio-json encode None with null and I've get the test error:

Expected :"{"name":"SomeName"[]}"
Actual   :"{"name":"SomeName"[,"nickName":null]}"

I checked the code and found the encoder for Option https://github.com/zio/zio-json/blob/52d007ee22f214d12e1706b016f149c3243c632c/zio-json/shared/src/main/scala/zio/json/encoder.scala#L188-L202

Any idea how I can encode it as a missing JSON field?

2

There are 2 best solutions below

0
On
implicit val OptionStringCodec: JsonCodec[Option[String]] = JsonCodec.string.xmap( s =>
    s match {
      case null | "" => None
      case s         => Some(s)
    },
    _.getOrElse("")
)
1
On

Note: I'm not familiar sith zio-json, there might be another way like a configuration to achieve the same thing.

Given the sample of code you linked, you can easily write an encoder that doesn't write anything in case of none by copying most of the code but modifying:

def unsafeEncode(oa: Option[A], indent: Option[Int], out: Write): Unit = oa match {
  case None    => () // out.write("null")
  case Some(a) => A.unsafeEncode(a, indent, out)
}