I’m pretty new to OCaml, so sorry for my dumminess.
I was looking for a way to validate some JSON String against a schema, I have see some libraries (yojson in particular), but I did not see any validation method.
There is a simple way or I should implement validation myself?
I’d suggest reading it all, but particularly the section on “Automatically Mapping JSON to OCaml Types,” which shows how you can use ATDgen with Yojson to do quite a bit (including validation).
Everything seems ok, except when I have some json that can contain different schemas in a value, for instance
{"type":1, "value":{"key1":"value1"}}
or
{"type":2, "value":{"key_1231":12}}
So in my case value can contain different json, I have tried using 'a and not defining so any type but I got an error when i try to compile the atd file.
Unfortunately these situations happen a lot in the wild.
Atdgen doesn’t provide a good mechanism that can handle all the situations at the moment. I have now a good sense of what a good design would feel like but I have limited/no time to work on it.
So, right now the solution that needs to be implemented manually involves the following steps:
In the ATD file, define type1, type2, etc. as usual so they map directly between json and OCaml types.
Define a variant type to represent all the json messages that need to exist under the same type. The tags are chosen freely by you (e.g. Type1 or something more meaningful).
[Write code to] read a json message first as a generic AST (returned by Yojson.Basic.from_string and alike).
[Write code to] inspect such tree and determine the tag and the value part (using pattern matching and Yojson.Basic.Util). You can rearrange the tree freely to produce and ATD-friendly structure for the value.
[Write code to] convert the value back to json (a string) and convert it to the desired OCaml type using the corresponding function generated by atdgen (e.g. type1_of_string (Yojson.Basic.to_string value_ast)).
Optionally, implement the reverse of steps 2-4 if you need to convert an OCaml message to json.
Here’s example.atd:
type type1 = { key1: string }
type type2 = { key2: int }
and example.ml:
(*
Handle json messages like these:
{"type":1, "value":{"key1":"value1"}}
{"type":2, "value":{"key_1231":12}}
*)
type msg = [
| `Type1 of Example_t.type1
| `Type2 of Example_t.type2
]
(*
Read a json message as an OCaml value of type `Example_t.msg`.
*)
let msg_of_string s =
let open Yojson.Basic.Util in
let ast = Yojson.Basic.from_string s in
let type_ = ast |> member "type" |> to_int in
let value_ast = ast |> member "value" in
let value_json = Yojson.Basic.to_string value_ast in
match type_ with
| 1 -> `Type1 (Example_j.type1_of_string value_json)
| 2 -> `Type2 (Example_j.type2_of_string value_json)
| _ -> failwith "Unsupported message type"