jacquard_common/types/
xrpc.rs

1use serde::{Deserialize, Serialize};
2use std::error::Error;
3use std::fmt::{self, Debug};
4
5use crate::IntoStatic;
6use crate::types::value::Data;
7
8/// Error type for encoding XRPC requests
9#[derive(Debug, thiserror::Error, miette::Diagnostic)]
10pub enum EncodeError {
11    /// Failed to serialize query parameters
12    #[error("Failed to serialize query: {0}")]
13    Query(
14        #[from]
15        #[source]
16        serde_html_form::ser::Error,
17    ),
18    /// Failed to serialize JSON body
19    #[error("Failed to serialize JSON: {0}")]
20    Json(
21        #[from]
22        #[source]
23        serde_json::Error,
24    ),
25    /// Other encoding error
26    #[error("Encoding error: {0}")]
27    Other(String),
28}
29
30/// XRPC method type
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
32pub enum XrpcMethod {
33    /// Query (HTTP GET)
34    Query,
35    /// Procedure (HTTP POST)
36    Procedure(&'static str),
37}
38
39impl XrpcMethod {
40    /// Get the HTTP method string
41    pub const fn as_str(&self) -> &'static str {
42        match self {
43            Self::Query => "GET",
44            Self::Procedure(_) => "POST",
45        }
46    }
47
48    /// Get the body encoding type for this method (procedures only)
49    pub const fn body_encoding(&self) -> Option<&'static str> {
50        match self {
51            Self::Query => None,
52            Self::Procedure(enc) => Some(enc),
53        }
54    }
55}
56
57/// Trait for XRPC request types (queries and procedures)
58///
59/// This trait provides metadata about XRPC endpoints including the NSID,
60/// HTTP method, encoding types, and associated output types.
61///
62/// The trait is implemented on the request parameters/input type itself.
63pub trait XrpcRequest: Serialize {
64    /// The NSID for this XRPC method
65    const NSID: &'static str;
66
67    /// XRPC method (query/GET or procedure/POST)
68    const METHOD: XrpcMethod;
69
70    /// Output encoding (MIME type)
71    const OUTPUT_ENCODING: &'static str;
72
73    /// Response output type
74    type Output<'de>: Deserialize<'de> + IntoStatic;
75
76    /// Error type for this request
77    type Err<'de>: Error + Deserialize<'de> + IntoStatic;
78
79    /// Encode the request body for procedures.
80    ///
81    /// Default implementation serializes to JSON. Override for non-JSON encodings.
82    fn encode_body(&self) -> Result<Vec<u8>, EncodeError> {
83        Ok(serde_json::to_vec(self)?)
84    }
85}
86
87/// Error type for XRPC endpoints that don't define any errors
88#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
89#[serde(bound(deserialize = "'de: 'a"))]
90pub struct GenericError<'a>(Data<'a>);
91
92impl fmt::Display for GenericError<'_> {
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        self.0.fmt(f)
95    }
96}
97
98impl Error for GenericError<'_> {}
99
100impl IntoStatic for GenericError<'_> {
101    type Output = GenericError<'static>;
102    fn into_static(self) -> Self::Output {
103        GenericError(self.0.into_static())
104    }
105}