Skip to main content

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}