Search code examples
reasonbucklescriptbs-json

How to convert Js.Json.t to Js.t('a)?


I have encoded an object via bs-json and want to send it as a data via post using bs-axios.

  33 │ let createTest = (p: Data.toBuyListItem) => inst->Instance.postData("/
       test", p |> Data.encodeToBuyListItem);
...
  This has type:
    Js.Json.t (defined as Js.Json.t)
  But somewhere wanted:
    Js.t('a)

p |> Data.encodeToBuyListItem is red. How to use the Js.Json.t value as data for a post request?

Edit:

Well, this works:

let createTest = (p: Data.toBuyListItem) => inst->Instance.postData("/test", [%raw "p"]);

but I would prefer a non-hacky solution (preferably using bs-json, since I am using that for decoding JSON)...


Solution

  • There's no way to safely convert a Js.Json.t to Js.t, as the latter represents a JavaScript object, and JSON doesn't just represent objects. But bs-axios seems to throw safety out the window anyway, so you could just cast it unsafely:

    external jsonToObjects : Js.Json.t => Js.t({..}) = "%identity";
    

    %identity is a general mechanism that can be used to cast between any two types, so this is as unsafe as it gets with regards to typing. You're basically saying "Look away while I swap these things around and trust me, I know what I'm doing". So make sure you do.

    Another alternative is to create a Js.t object directly. Reason has built-in syntax for that, so it's pretty easy:

    let obj = {
      "data": someData
    };
    

    someData here can be any value, even a Js.Json.t value, but that also means you can pass in values that aren't serializable, which Js.Json.t protects you against.

    Given that the bs-axios API is inherently unsafe there's a minor safety trade-off here, but I think whichever is easiest will do fine.