garyb / purescript-codec-argonaut

Bi-directional JSON codecs for argonaut
MIT License
39 stars 16 forks source link

Decoding Maybe fields #26

Closed alebon closed 5 years ago

alebon commented 5 years ago

Maybe I missunderstood on how to use the library but I am not able to get it to work with Maybe values.

`type TestmodelRec = { id :: String , intValue :: Int , maybeIntValue :: Maybe Int }

newtype Testmodel = Testmodel TestmodelRec

derive instance newtypeTestmodel ∷ Newtype Testmodel _

codecTestmodel ∷ CA.JsonCodec Testmodel codecTestmodel = wrapIso Testmodel (CAR.object "Testmodel" { id: CA.string , intValue: CA.int , maybeIntValue: CAC.maybe CA.int })

decodeTestmodel ∷ J.Json -> Either CA.JsonDecodeError Testmodel decodeTestmodel = decode codecTestmodel`

This is more or less the model I am using. Throwing some Json at it with maybeIntValue:4 gives me the error:

Error: (Named "Testmodel" (AtKey "maybeIntValue" (Named "Maybe" (TypeMismatch "Object"))))

Same if maybeIntValue is set to null in the Json representation.

CAC is the Common version. If I use the Compat version, it works with 4 and null. But it is giving me a MissingValue if maybeIntValue is not set. I think this is expected. I understood that the Common module gives me the same behaviour but will decode to Nothing if the property is missing within the Json representation.

garyb commented 5 years ago

The Common version is the "most strict": it doesn't encode as null, it uses an tagged representation. It's more intended for serialisation formats that are under the control of the app, not reading a format produced by something else, since it's unlikely anything else will produce the correct JSON structure to match it.

The Compat version does encode with null, it's included for compatibility with the argonaut EncodeJson / DecodeJson instances. The null encoding is problematic as it cannot accurately represent nested Maybe values: Nothing and Just Nothing will both be encoded as null with this scheme.

There isn't a maybe codec that works with the field not existing, the reason for that is the failure happens before it even gets to the maybe: it's failing at the object / record codec instead, as they assume all fields to be present.

The motivation for the library was the first case (fully app-determined serialisation schema), so I've not given much thought to the missing fields case yet, since that only arises when writing codecs for existing schemas. I think the easiest thing for now might be to use a addDefaultField migration to add the potentially absent field, setting a null default value, and then use the Compat version of the codec maybe codec.

alebon commented 5 years ago

Thanks for the explanation :)