ahrefs / atd

Static types for JSON APIs
Other
315 stars 52 forks source link

Extracting strings from variants includes the escaped quotes #374

Closed rbjorklin closed 11 months ago

rbjorklin commented 11 months ago

This might be expected behaviour but I nonetheless was surprised by it. See the following example:

my_type.atd:

type side = [
    | Buy <json name="B">
    | Sell <json name="S">
]

type my_type = {
    my_key : side;
    my_string : string;
}
let t = My_type_j.my_type_of_string {| {"my_key": "B", "my_string": "hey"} |}

let () =
  Printf.printf "%s" (My_type_j.string_of_my_type t);
  (* Prints: {"my_key":"B", "my_string": "hey"} *)

  My_type_j.string_of_side t.my_key;
  (* Evaluates to: "\"B\"" in utop *)

  Printf.printf "%s" (My_type_j.string_of_side t.my_key);
  (* Prints: "B"
  Would have expected: B without quotes *)

  Printf.printf "%s" t.my_string;
  (* Prints: hey
  without quotes as expected *)
mjambon commented 11 months ago

Yes, the string_of_ converters produce JSON data. A JSON string is always double-quoted, so that's what you get. There's no function to give you directly the unquoted string. Your options include:

rbjorklin commented 11 months ago

Thanks @mjambon for the prompt and informative response! I've found atd very useful and appreciate all the time and effort you and the other maintainers have put into the project!

Armed with this information I'm going to mark this issue as closed.

rbjorklin commented 11 months ago

Another comment if someone finds their way here in the future. Unfortunately the [@@ deriving show] route doesn't work either as that also prints extra characters.


My_type_j.show_side `Buy;;
(* Note the backtick in the string: "`Buy" *)

EDIT: Trying to use <ocaml repr="classic"> will only make it worse as then the module name is also included in the returned string.

EDIT2: I found this to be the easiest solution:

side.atd:

type order = {
  side : string wrap <ocaml t="My_type.t" wrap="My_type.of_string" unwrap="My_type.to_string">;
}

my_type.ml:

type t =
  | Buy
  | Sell

let to_string = function
  | Buy -> "BUY"
  | Sell -> "SELL"

let of_string = function
  | "BUY" -> Buy
  | "SELL" -> Sell
[@@ocaml.warning "-partial-match"]
mjambon commented 11 months ago

EDIT: Trying to use will only make it worse as then the module name is also included in the returned string.

ppx_show has an option to not print the module name:

[@@deriving show { with_path = false }]