thoth-org/Thoth.Json

Add `fromJsonValue` or `fromObject` helper

Closed this issue · 3 comments

I got a little stuck when trying to decode a JsonValue (which is an object) because turning it into a string gave me "[object Object]", which obviously won't decode correctly. I resolved this with Decode.fromValue "" ..., but this doesn't feel quite as intuitive to me.

I think adding a Decode.fromObject or Decode.fromJsonValue will make the intended use path pretty clear and help reduce confusion from other newbies like myself.

This seems rather straightforward, so I'm more than willing to take a stab at it. I'm curious if this was intentionally avoided for some reason, though.

This is kind of intended because we don't know at what place of the path it is being called. I know that in the past some people called Decode.fromValue deep in their JSON structure.

When calling it at the root, you should call Decode.fromValue "$" ... $ meaning the root of the JSON and will be used for reporting the correct path in case of error.

Also, Decode.fromValue is exposed but it was more intended to be an internal feature of Thoth.Json.

Personally, I think what is missing is probably a doc comment explaining how to use it, so people can have the explanation available from their IDE tooltips.

This is kind of intended because we don't know at what place of the path it is being called. I know that in the past some people called Decode.fromValue deep in their JSON structure.

Hmm, I think I'm missing something. If I have a type with a property that's a JsonValue, wouldn't I be able to decode that value from the root? Or is the whole wrapping object given with the path to that value? Would creating a function Decode.fromRoot help here / do what I want?

I'm fine adding some comments if you don't think this kind of function would be helpful.

njlr commented

I think what you are looking for would be like this:

module Decode =

  let fromRootValue (dec : Decoder<_>) = 
    Decode.fromValue "$" dec

If you have a type containing a JsonValue property it might look like this:

type Foo =
  {
    X : int
    J : JsonValue
  }

module Decode =

  let foo =
    Decode.object
      (fun get ->
        {
          X = get.Required.Field "x" Decode.int
          J = get.Required.Field "j" Decode.value
        })

which can decode JSON like:

{
  "x": 123,
  "j": {
    "any": "thing"
  }
}