Closed mudrz closed 2 years ago
You can define you own, manually written, encoding / decoding function https://github.com/janestreet/ppx_yojson_conv/blob/master/test/ppx_yojson_test.ml#L485
thanks @hhugo ! Not sure if there is a more elegant solution, but I ended up with something like this:
module Indexed_record : sig
type 'a t = 'a Map.M(String).t [@@deriving yojson, sexp]
end = struct
type 'a t = 'a Map.M(String).t [@@deriving sexp]
let t_of_yojson of_yojson yojson =
match yojson with
| `Null | `Bool _ | `Int _ | `Intlit _ | `Float _ | `String _ | `List _
| `Tuple _ | `Variant _ ->
failwith "Invalid type"
| `Assoc xs ->
let xs = List.map xs ~f:(fun (k, v) -> (k, of_yojson v)) in
Map.of_alist_exn (module String) xs
let yojson_of_t to_yojson v =
let xs =
let v = Map.map v ~f:to_yojson in
Map.to_alist v
in
`Assoc xs
end
with uses:
type user = {
name: string; [@key "Name"]
}[@@deriving yojson]
type my_thing = {
users: user Indexed_record.t; [@key "Users"]
}[@@deriving yojson]
it's also convenient to provide alternatives
module Indexed_list : sig
type 'a t = 'a list [@@deriving yojson, sexp]
end = struct
type 'a t = 'a list [@@deriving sexp]
let t_of_yojson of_yojson yojson =
match yojson with
| `Null | `Bool _ | `Int _ | `Intlit _ | `Float _ | `String _ | `List _
| `Tuple _ | `Variant _ ->
failwith "Invalid type"
| `Assoc xs -> List.map xs ~f:(fun (_k, v) -> of_yojson v)
let yojson_of_t to_yojson v =
let xs = List.mapi v ~f:(fun i x -> (Int.to_string i, to_yojson x)) in
`Assoc xs
end
@mudrz, that is what I had in mind. You can also use https://github.com/janestreet/ppx_yojson_conv_lib/blob/master/yojson_conv.mli#L119 to handle the error case.
even cleaner, thanks again!
module Indexed_list : sig
type 'a t = 'a list [@@deriving yojson, sexp]
end = struct
type 'a t = 'a list [@@deriving sexp]
let t_of_yojson of_yojson yojson =
match yojson with
| `Assoc xs -> List.map xs ~f:(fun (_k, v) -> of_yojson v)
| _ ->
Ppx_yojson_conv_lib.Yojson_conv.of_yojson_error
"indexed_list_of_yojson: tuple list needed" yojson
let yojson_of_t to_yojson v =
let xs = List.mapi v ~f:(fun i x -> (Int.to_string i, to_yojson x)) in
`Assoc xs
end
I have to interact with an API, that returns data with the following format:
essentially
Users
is an array encoded in JSON as a record, with indexes as keys (I can't change that format) -> the keys are unknownIs there any way to represent this with
ppx_yojson_conv
? For example to convert it to a hash table / map(string, user) Map.t
where user is:Is it possible to 'ignore' the contents of
Users
? (using anopaque
attribute doesn't seem to work since you have to specify the type)