Reputation: 1816
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.
Upvotes: 3
Views: 896
Reputation: 29106
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))
));
Upvotes: 6
Reputation: 1333
I see you're using bs-json so one way to do this is to take advantage of the fact that Json.Decode.optional
returns None
if a decode fails. For your example:
type period = {
start: string,
end_: string,
};
type periodVariant =
| String(string)
| Period(period);
let periodVariantDecode = json => {
let periodString = json |> Json.Decode.(optional(string));
switch (periodString) {
| Some(periodString) => String(periodString)
| None =>
let periodObj =
Json.Decode.{
start: json |> field("start", string),
end_: json |> field("end", string),
};
Period(periodObj);
};
};
That should compile with periodVariantDecode
being of type Js.Json.t => periodVariant
. I'm not sure if it's the idiomatic way to go though!
Upvotes: 2