Fail to convert to json a record with union types with websharper

250 views Asked by At

I'm using websharper to convert records/unions to post to a API in json. This are the declarations:

[<NamedUnionCases "Icon">]
type IconName =
    | Aaabattery
    | Abacus

[<NamedUnionCases>]
type Size =
    | H1
    | H2
    | H3
    | H4
    | H5


type Icon = {title:string; name:IconName; size:Size; updated:DateTime; }


Icon {title = "hello";
  name = Aaabattery;
  size = H1;
  updated = 11/06/2015 3:18:29 p. m.;}

This is how I encode:

let ToJString (jP:Core.Json.Provider, msg:Widget) =
        let enc = jP.GetEncoder<Widget>()

        enc.Encode msg
        |> jP.Pack
        |> Core.Json.Stringify


printfn "D:"
let j = Core.Json.Provider.Create()
let data =  ToJString(j, widget)
printfn "D: %A" data

The program never reach the last printfn "D: %A" data. However, If I turn the unions to enum or remove it them worked. What is missing?

1

There are 1 answers

0
Tarmil On

[<NamedUnionCases>] without argument relies on the names of the arguments to disambiguate between cases. For example, with the following type:

[<NamedUnionCases>]
type Foo =
    | Case1 of x: int
    | Case2 of y: int

values are serialized as either {"x":123} or {"y":123}, so deserialization is possible by checking which fields are present. But in your type Size, all cases have zero argument so they would essentially all be serialized as {}, so the deserializer wouldn't know which case to choose.

There are several solutions:

  • If you want to serialize these values as objects with a field telling which case it is, use [<NamedUnionCases "fieldName">] to get eg. {"fieldName":"H1"}.
  • If you want to serialize them as constant numbers or strings, use the Constant attribute like this:

    type Size =
        | [<Constant 1>] H1
        | [<Constant 2>] H2
        | [<Constant 3>] H3
        | [<Constant 4>] H4
        | [<Constant 5>] H5
    

    this way for example H1 will be serialized simply as 1.