How do you convert a record to a js object?


#1

I have a rest API that is expecting json format. I am passing in a record currently which is failing. When I Js.Log the record, I can see that it is a funny array structure, which certainly won’t fly. I assume there is a way I could “convert” that record to a json/js object, but I’m not finding the answer yet.


#2

I found this in the documentation: https://bucklescript.github.io/docs/en/generate-converters-accessors.html#convert-between-jst-object-and-record

But that seems to only help me with one level of nesting. I have a prop with an array of items, each of which has another nested object. Still not sure how to convert those.


#3

I’ve run into the same pain point (see Logging reason values). I think that your two options are:

  1. Create a parallel set of Js.t objects (like the ones your link refers to) that mirror your Reason types at every level and semi-manually write the conversion functions (I say semi-manually because as you know the leaf-nodes can just use jsConverter).

  2. Convert your data structures to a Js.Json.t. Instead of creating a parallel set of types, one js type for each Reason type, each of your Reason types would have a conversion function to Js.Json.t. I think being able to derive json, similar to jsConverter, but in a recursive way that goes all the way through your data structures would be extremely valuable. I’m trying to convince the relevant people, but no serious traction yet.

P.S. I haven’t had the time to play around with Js.Json.t too much yet, but here are two relevant links:


#4

Your best bet is to use bs-json to encode your record as json. Though you could do the same with the built in Js_json library.

Heres an example:

module Encode = {
  let toJson = credential =>
    Json.Encode.(
      object_([
        ("id", credential.id |> int),
        ("created", credential.created |> int),
        ("updated", credential.updated |> int),
        ("client_id", credential.clientId |> int),
        ("foreign_credential_id", credential.foreignCredentialId |> string),
        (
          "algorithm",
          credential.algorithm |> Hash.algorithmToString |> string
        ),
        ("salt", credential.salt |> string),
        ("derived_key", credential.derivedKey |> string)
      ])
    );
  let arrayToJson = arr =>
    Belt_Array.map(arr, toJson) |> Json.Encode.jsonArray;
  let listToJson = l => Belt_List.toArray(l) |> arrayToJson;
};

#5

I actually faced this same issue last week, and spent a lot of time learning how to fetch JSON, parse and decode it, and then encode something back to JSON.

I’m working on a blog post that explains everything in detail. However, you can preview the working example code here:

See the app.re file for all the decoding / encoding action.


#6

I have written a post on medium: https://medium.com/@DmytroGladkyi/decode-and-encode-json-in-reasonml-2d484c65cf4e. It has info on how to decode/encode JSON into/from ReasonML structures. In our production code I use this approach to convert ReasonML objects into JSON to be sent into websocket (from JS lib).


#7

in resources limited environment like browser (especially on mobile), any operations is costly so I would suggest you to define a Js.t type with the shape of the object and use %identity converter to convert from Js.Json.t to Js.t