My agentic slop goes here. Not intended for anyone else!
1(** JMAP Request Object
2
3 A Request object represents a single HTTP POST to the JMAP API endpoint.
4 It contains capabilities the client wants to use and a list of method calls.
5
6 Reference: RFC 8620 Section 3.3
7 Test files:
8 - test/data/core/request_echo.json
9 - test/data/core/request_get.json
10 - All request_*.json files
11*)
12
13(** Main request type *)
14type t = {
15 using : Jmap_capability.t list;
16 method_calls : Jmap_invocation.invocation_list;
17 created_ids : (Jmap_id.t * Jmap_id.t) list option;
18}
19
20(** Accessors *)
21let using t = t.using
22let method_calls t = t.method_calls
23let created_ids t = t.created_ids
24
25(** Create a request *)
26let make ?(created_ids=None) ~using method_calls =
27 { using; method_calls; created_ids }
28
29(** Parser submodule *)
30module Parser = struct
31 (** Parse request from JSON value.
32 Test files: test/data/core/request_*.json *)
33 let of_json json =
34 match json with
35 | `O fields ->
36 let get_field name =
37 match List.assoc_opt name fields with
38 | Some v -> v
39 | None -> raise (Jmap_error.Parse_error (Printf.sprintf "Missing field: %s" name))
40 in
41
42 (* Parse using *)
43 let using =
44 match get_field "using" with
45 | `A caps ->
46 List.map (function
47 | `String cap -> Jmap_capability.of_string cap
48 | _ -> raise (Jmap_error.Parse_error "using values must be strings")
49 ) caps
50 | _ -> raise (Jmap_error.Parse_error "using must be an array")
51 in
52
53 (* Parse methodCalls *)
54 let method_calls =
55 match get_field "methodCalls" with
56 | `A calls -> List.map Jmap_invocation.of_json calls
57 | _ -> raise (Jmap_error.Parse_error "methodCalls must be an array")
58 in
59
60 (* Parse createdIds (optional) *)
61 let created_ids =
62 match List.assoc_opt "createdIds" fields with
63 | Some (`O ids) ->
64 Some (List.map (fun (k, v) ->
65 match v with
66 | `String id -> (Jmap_id.of_string k, Jmap_id.of_string id)
67 | _ -> raise (Jmap_error.Parse_error "createdIds values must be strings")
68 ) ids)
69 | Some _ -> raise (Jmap_error.Parse_error "createdIds must be an object")
70 | None -> None
71 in
72
73 { using; method_calls; created_ids }
74 | _ -> raise (Jmap_error.Parse_error "Request must be a JSON object")
75
76 (** Parse request from JSON string *)
77 let of_string s =
78 try
79 of_json (Ezjsonm.from_string s)
80 with
81 | Ezjsonm.Parse_error (_, msg) ->
82 raise (Jmap_error.Parse_error ("Invalid JSON: " ^ msg))
83
84 (** Parse request from input channel *)
85 let of_channel ic =
86 try
87 of_json (Ezjsonm.from_channel ic)
88 with
89 | Ezjsonm.Parse_error (_, msg) ->
90 raise (Jmap_error.Parse_error ("Invalid JSON: " ^ msg))
91end
92
93(** Serialization *)
94let to_json t =
95 let using_json = `A (List.map (fun cap ->
96 `String (Jmap_capability.to_string cap)
97 ) t.using) in
98
99 let method_calls_json = `A (List.map (fun (Jmap_invocation.Packed inv) ->
100 Jmap_invocation.to_json inv
101 ) t.method_calls) in
102
103 let fields = [
104 ("using", using_json);
105 ("methodCalls", method_calls_json);
106 ] in
107
108 let fields = match t.created_ids with
109 | Some ids ->
110 let ids_json = `O (List.map (fun (k, v) ->
111 (Jmap_id.to_string k, `String (Jmap_id.to_string v))
112 ) ids) in
113 fields @ [("createdIds", ids_json)]
114 | None -> fields
115 in
116
117 `O fields