Serializing a record to JSON with ppx_yojson_conv?

So I’m a complete n00b to OCaml (but not a beginner programmer, the ML style is a bit confusing coming from self teaching) and I’ve been searching endlessly and reading source code to figure out how to serialize a record type into a string… What am I missing? The word serialize never appears in any docs, anywhere. There’s either no examples or no info on how to use the functions themselves, or they’re parsing not generating JSON.

I need to know if I’m just dumb or not, [@@deriving yojson] compiles just fine but I have absolutely no idea how to actually get it to return back a string or accept the type. Do I need to use the deriving in an interface file? Where did any of you learn how to do this?

If I’m dumb please delete this, thanks!

PS: I can also get s-expressions to work fine with my derived structs, I think I’m missing some etiquette for how ppx_deriving works?

2 Likes

Hi @SeedyROM,

Using ppx_yojson_conv to go to & from JSON strings should look something like this:

type t = { foo : string; bar : int } [@@deriving yojson]

let to_json_string t = Yojson.Safe.to_string (yojson_of_t t)
let of_json_string s = t_of_yojson (Yojson.Safe.from_string s)

You’ll also need to tell your build system about the PPX in some way. If you’re using Dune:

(executable  ;; or 'library', or 'test'
 ...
 (preprocess (pps ppx_yojson_conv)))

Unfortunately, if you don’t declare a dependency on some ppx_deriving PPX then the [@@deriving ...] will just silently fail to generate anything. If you’re getting errors of the form "Unbound value: yojson_of_t" then that’s probably the what’s going on.

4 Likes

@CraigFe
Interesting! I wasn’t getting silent failures, since I was using the ppx_jane pps. However the part about defining the to and of functions (edit: rather the code inside those methods) is what I was missing I think? I’m not at home right now so I can’t check, but I think I was expecting something more like Rust’s derive which will code gen those types for me.

I’m gonna check in a bit, thanks for quick response! I also think I’m gonna make a blog post on some of these gaps in docs coming from other langs and misconceptions I’ve had.

Thanks so much.

2 Likes

Right, the PPX extension codegens the t_of_yojson and yojson_of_t for you, to-and-from the type of Yojson values. @CraigFe is just adding a nice wrapper, to go back-and-forth to strings. There are functions in the Yojson package to go back-and-forth to other sources/sinks (e.g. channels).

P.S. the “t” in t_of_yojson comes from the name of the type in the typedef, which was “t”.

4 Likes

Yup, it was those generated functions I was looking for, the wrapper finally got it to click for me. My brain went blank on the t meaning my type as well.

Thanks to both of ya’ll for helping me out! Cheers.

2 Likes

Imho, this is a slightly bad naming convention. When generating the functions for a type t, the t_of/of_t parts should be left out from the names. For other names, it’s reasonable to put the type names in the functions.

Yawar, I’m curious why you think this. What naming convention would you think is better?

I think this is better:

If the type is called t , the functions generated are {of,to}_yojson instead of t_{of,to}_yojson .

From: GitHub - ocaml-ppx/ppx_deriving_yojson: A Yojson codec generator for OCaml.

The reason is, if you have a type t, it’s certainly going to be in a module named something meaningful i.e. the actual name of the domain entity that the type represents. E.g. module Person = .... Then the conversion functions will be accessible as Person.of_yojson and Person.to_yojson, instead of Person.t_of_yojson/Person.t_to_yojson.

1 Like

Ah, I see it now. You don’t mean “in general”, but rather specifically for the case of a type “t”. Gotit. Thank you for clarifying. I buy your argument.

3 Likes