Search code examples
jsonreasonbucklescriptbs-json

Convert JSON field to ReasonML variant


I have a JSON structure that contains a field period that can either be an object or a string. I already have the variant ready in my code, and it's working fine:

type period = {
  start: string,
  end_: string,
};

type periodVariant =
  | String(string)
  | Period(period);

The problem is when I try to cast the input JSON to the variant type: I simply don't know how to do that. Here's what my attempt looks like:

let periodVariantDecode = (json: Js.Json.t): periodVariant => {
  switch(json) {
  | String(string) => String(Json.Decode.string(string))
  | period => Period(Json.Decode.{
      start: period |> field("start", string),
      end_: period |> field("end", string),
    })
  };
};

Now, of course that doesn't work because I'm trying to match something that is still of type Js.Json.t against String which is part of my periodVariant, but I don't know how to achieve what I want.


Solution

  • This is what either is for. Along with map to conveniently "lift" an existing decoder to your variant type.

    type period = {
      start: string,
      end_:  string,
    };
    
    type periodVariant =
      | String(string)
      | Period(period);
    
    let period = json =>
      Json.Decode.{
        start: json |> field("start", string),
        end_:  json |> field("end", string),
      };
    
    let periodVariantDecode =
      Json.Decode.(either(
        period |> map(p => Period(p)),
        string |> map(s => String(s))
      ));