JSON Validation?

Hi everyone,

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?

Thanks!

Hi Gabriele,

Have you checked out the chapter on JSON in “Real World OCaml” yet?

See here:

https://realworldocaml.org/v1/en/html/handling-json-data.html

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).

Good luck!

T

1 Like

Hi T,

Thank you very much, I have started reading about ATDgen, I’m using the version 2 of that book
https://dev.realworldocaml.org/15-json.html

Thanks again!

1 Like

Hi all,

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.

Any suggestion?
Thanks

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:

  1. In the ATD file, define type1, type2, etc. as usual so they map directly between json and OCaml types.
  2. 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).
  3. [Write code to] read a json message first as a generic AST (returned by Yojson.Basic.from_string and alike).
  4. [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.
  5. [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)).
  6. 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"
2 Likes

Thank you, this seems a reasonable trade off, I’ll start to implement in this way, hoping everything goes well.

Many Thanks!