io_jmap/rfc8620/request.rs
1//! JMAP request/response plumbing (RFC 8620 §3): the Request and Response
2//! objects, the batch builder generating call ids, and the result reference
3//! used to back-reference an earlier call within a batch.
4
5use alloc::{collections::BTreeMap, format, string::String, vec::Vec};
6
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9
10/// A JMAP result reference (RFC 8620 §3.7) used to back-reference an
11/// earlier method call's result within a batch request.
12#[derive(Serialize)]
13#[serde(rename_all = "camelCase")]
14pub struct JmapResultReference<'a> {
15 /// The call id of the method call to reference.
16 pub result_of: &'a str,
17 /// The name of the referenced method.
18 pub name: &'static str,
19 /// The JSON pointer into the referenced result.
20 pub path: &'static str,
21}
22
23/// The JMAP Request object (RFC 8620 §3.3).
24#[derive(Clone, Debug, Serialize)]
25#[serde(rename_all = "camelCase")]
26pub struct JmapRequest {
27 /// Capability URNs required by the methods in this request.
28 pub using: Vec<String>,
29 /// The method calls to execute, as `(methodName, args, callId)`
30 /// tuples.
31 pub method_calls: Vec<(String, Value, String)>,
32 /// Client-assigned IDs for newly created objects.
33 #[serde(skip_serializing_if = "Option::is_none")]
34 pub created_ids: Option<BTreeMap<String, String>>,
35}
36
37/// The JMAP Response object (RFC 8620 §3.4).
38#[derive(Clone, Debug, Deserialize)]
39#[serde(rename_all = "camelCase")]
40pub struct JmapResponse {
41 /// Method responses in `(methodName, result, callId)` format.
42 ///
43 /// If a method failed, `methodName` is `"error"` and `result` is a
44 /// [`crate::rfc8620::error::JmapMethodError`] object.
45 pub method_responses: Vec<(String, Value, String)>,
46 /// Server-assigned IDs for objects created by this request.
47 #[serde(default)]
48 pub created_ids: Option<BTreeMap<String, String>>,
49 /// The current state of the session after this request.
50 pub session_state: String,
51}
52
53/// Builder for batched JMAP requests: multiple method calls in one HTTP
54/// request, with generated call IDs for [`JmapResultReference`] back-refs.
55#[derive(Debug, Default)]
56pub struct JmapBatch {
57 calls: Vec<(String, Value, String)>,
58 counter: usize,
59}
60
61impl JmapBatch {
62 /// Creates a new empty batch.
63 pub fn new() -> Self {
64 Self::default()
65 }
66
67 /// Adds a method call. Returns the call ID (`"c0"`, `"c1"`, …) for use in
68 /// back-references from later calls.
69 pub fn add(&mut self, method: impl Into<String>, args: Value) -> String {
70 let call_id = format!("c{}", self.counter);
71 self.counter += 1;
72 self.calls.push((method.into(), args, call_id.clone()));
73 call_id
74 }
75
76 /// Consumes the batch and returns a [`JmapRequest`].
77 pub fn into_request(self, using: Vec<String>) -> JmapRequest {
78 JmapRequest {
79 using,
80 method_calls: self.calls,
81 created_ids: None,
82 }
83 }
84}