turbomcp_protocol/
jsonrpc.rs

1//! # JSON-RPC 2.0 Implementation
2//!
3//! This module provides a complete implementation of JSON-RPC 2.0 protocol
4//! with support for batching, streaming, and MCP-specific extensions.
5
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7use serde_json::Value;
8use std::fmt;
9
10use crate::types::RequestId;
11
12/// JSON-RPC version constant
13pub const JSONRPC_VERSION: &str = "2.0";
14
15/// JSON-RPC version type
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct JsonRpcVersion;
18
19impl Serialize for JsonRpcVersion {
20    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
21    where
22        S: Serializer,
23    {
24        serializer.serialize_str(JSONRPC_VERSION)
25    }
26}
27
28impl<'de> Deserialize<'de> for JsonRpcVersion {
29    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
30    where
31        D: Deserializer<'de>,
32    {
33        let version = String::deserialize(deserializer)?;
34        if version == JSONRPC_VERSION {
35            Ok(JsonRpcVersion)
36        } else {
37            Err(serde::de::Error::custom(format!(
38                "Invalid JSON-RPC version: expected '{JSONRPC_VERSION}', got '{version}'"
39            )))
40        }
41    }
42}
43
44/// JSON-RPC request message
45#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct JsonRpcRequest {
47    /// JSON-RPC version
48    pub jsonrpc: JsonRpcVersion,
49    /// Request method name
50    pub method: String,
51    /// Request parameters
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub params: Option<Value>,
54    /// Request identifier
55    pub id: RequestId,
56}
57
58/// JSON-RPC response payload - ensures mutual exclusion of result and error
59#[derive(Debug, Clone, Serialize, Deserialize)]
60#[serde(untagged)]
61pub enum JsonRpcResponsePayload {
62    /// Successful response with result
63    Success {
64        /// Response result
65        result: Value,
66    },
67    /// Error response
68    Error {
69        /// Response error
70        error: JsonRpcError,
71    },
72}
73
74/// JSON-RPC response message
75#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct JsonRpcResponse {
77    /// JSON-RPC version
78    pub jsonrpc: JsonRpcVersion,
79    /// Response payload (either result or error, never both)
80    #[serde(flatten)]
81    pub payload: JsonRpcResponsePayload,
82    /// Request identifier (required except for parse errors)
83    pub id: ResponseId,
84}
85
86/// Response ID - handles the special case where parse errors have null ID
87#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
88#[serde(transparent)]
89pub struct ResponseId(pub Option<RequestId>);
90
91impl ResponseId {
92    /// Create a response ID for a normal response
93    pub fn from_request(id: RequestId) -> Self {
94        Self(Some(id))
95    }
96
97    /// Create a null response ID for parse errors
98    pub fn null() -> Self {
99        Self(None)
100    }
101
102    /// Get the request ID if present
103    pub fn as_request_id(&self) -> Option<&RequestId> {
104        self.0.as_ref()
105    }
106
107    /// Check if this is a null ID (parse error)
108    pub fn is_null(&self) -> bool {
109        self.0.is_none()
110    }
111}
112
113/// JSON-RPC notification message (no response expected)
114#[derive(Debug, Clone, Serialize, Deserialize)]
115pub struct JsonRpcNotification {
116    /// JSON-RPC version
117    pub jsonrpc: JsonRpcVersion,
118    /// Notification method name
119    pub method: String,
120    /// Notification parameters
121    #[serde(skip_serializing_if = "Option::is_none")]
122    pub params: Option<Value>,
123}
124
125/// JSON-RPC error object
126#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
127pub struct JsonRpcError {
128    /// Error code
129    pub code: i32,
130    /// Error message
131    pub message: String,
132    /// Additional error data
133    #[serde(skip_serializing_if = "Option::is_none")]
134    pub data: Option<Value>,
135}
136
137impl JsonRpcError {
138    /// Create a new JSON-RPC error
139    pub fn new(code: i32, message: impl Into<String>) -> Self {
140        Self {
141            code,
142            message: message.into(),
143            data: None,
144        }
145    }
146
147    /// Create a new JSON-RPC error with additional data
148    pub fn with_data(code: i32, message: impl Into<String>, data: Value) -> Self {
149        Self {
150            code,
151            message: message.into(),
152            data: Some(data),
153        }
154    }
155
156    /// Create a parse error (-32700)
157    pub fn parse_error() -> Self {
158        Self::new(-32700, "Parse error")
159    }
160
161    /// Create a parse error with details
162    pub fn parse_error_with_details(details: impl Into<String>) -> Self {
163        Self::with_data(
164            -32700,
165            "Parse error",
166            serde_json::json!({ "details": details.into() }),
167        )
168    }
169
170    /// Create an invalid request error (-32600)
171    pub fn invalid_request() -> Self {
172        Self::new(-32600, "Invalid Request")
173    }
174
175    /// Create an invalid request error with reason
176    pub fn invalid_request_with_reason(reason: impl Into<String>) -> Self {
177        Self::with_data(
178            -32600,
179            "Invalid Request",
180            serde_json::json!({ "reason": reason.into() }),
181        )
182    }
183
184    /// Create a method not found error (-32601)
185    pub fn method_not_found(method: &str) -> Self {
186        Self::new(-32601, format!("Method not found: {method}"))
187    }
188
189    /// Create an invalid params error (-32602)
190    pub fn invalid_params(details: &str) -> Self {
191        Self::new(-32602, format!("Invalid params: {details}"))
192    }
193
194    /// Create an internal error (-32603)
195    pub fn internal_error(details: &str) -> Self {
196        Self::new(-32603, format!("Internal error: {details}"))
197    }
198
199    /// Check if this is a parse error
200    pub fn is_parse_error(&self) -> bool {
201        self.code == -32700
202    }
203
204    /// Check if this is an invalid request error
205    pub fn is_invalid_request(&self) -> bool {
206        self.code == -32600
207    }
208
209    /// Get the error code
210    pub fn code(&self) -> i32 {
211        self.code
212    }
213}
214
215/// JSON-RPC batch request/response
216///
217/// **IMPORTANT**: JSON-RPC batching is NOT supported in MCP 2025-06-18 specification.
218/// This type exists only for defensive deserialization and will return errors if used.
219/// Per MCP spec changelog (PR #416), batch support was explicitly removed.
220///
221/// Do not use this type in new code. It will be removed in a future version.
222#[derive(Debug, Clone, Serialize, Deserialize)]
223#[serde(transparent)]
224#[deprecated(
225    since = "2.2.3",
226    note = "JSON-RPC batching removed from MCP 2025-06-18 spec (PR #416). This type exists only for defensive handling and will be removed."
227)]
228pub struct JsonRpcBatch<T> {
229    /// Batch items
230    pub items: Vec<T>,
231}
232
233/// Standard JSON-RPC error codes
234#[derive(Debug, Clone, Copy, PartialEq, Eq)]
235pub enum JsonRpcErrorCode {
236    /// Parse error (-32700)
237    ParseError,
238    /// Invalid request (-32600)
239    InvalidRequest,
240    /// Method not found (-32601)
241    MethodNotFound,
242    /// Invalid params (-32602)
243    InvalidParams,
244    /// Internal error (-32603)
245    InternalError,
246    /// Application-defined error
247    ApplicationError(i32),
248}
249
250impl JsonRpcErrorCode {
251    /// Get the numeric error code
252    pub fn code(&self) -> i32 {
253        match self {
254            Self::ParseError => -32700,
255            Self::InvalidRequest => -32600,
256            Self::MethodNotFound => -32601,
257            Self::InvalidParams => -32602,
258            Self::InternalError => -32603,
259            Self::ApplicationError(code) => *code,
260        }
261    }
262
263    /// Get the standard error message
264    pub fn message(&self) -> &'static str {
265        match self {
266            Self::ParseError => "Parse error",
267            Self::InvalidRequest => "Invalid Request",
268            Self::MethodNotFound => "Method not found",
269            Self::InvalidParams => "Invalid params",
270            Self::InternalError => "Internal error",
271            Self::ApplicationError(_) => "Application error",
272        }
273    }
274}
275
276impl fmt::Display for JsonRpcErrorCode {
277    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278        write!(f, "{} ({})", self.message(), self.code())
279    }
280}
281
282impl From<JsonRpcErrorCode> for JsonRpcError {
283    fn from(code: JsonRpcErrorCode) -> Self {
284        Self {
285            code: code.code(),
286            message: code.message().to_string(),
287            data: None,
288        }
289    }
290}
291
292impl From<i32> for JsonRpcErrorCode {
293    fn from(code: i32) -> Self {
294        match code {
295            -32700 => Self::ParseError,
296            -32600 => Self::InvalidRequest,
297            -32601 => Self::MethodNotFound,
298            -32602 => Self::InvalidParams,
299            -32603 => Self::InternalError,
300            other => Self::ApplicationError(other),
301        }
302    }
303}
304
305/// JSON-RPC message type (union of request, response, notification)
306///
307/// **MCP 2025-06-18 Compliance Note:**
308/// Batch variants exist only for defensive deserialization and are NOT supported
309/// per MCP specification (PR #416 removed batch support). They will return errors if encountered.
310#[derive(Debug, Clone, Serialize, Deserialize)]
311#[serde(untagged)]
312pub enum JsonRpcMessage {
313    /// Request message (MCP-compliant)
314    Request(JsonRpcRequest),
315    /// Response message (MCP-compliant)
316    Response(JsonRpcResponse),
317    /// Notification message (MCP-compliant)
318    Notification(JsonRpcNotification),
319    /// Batch of messages (NOT SUPPORTED - defensive deserialization only)
320    ///
321    /// **Deprecated**: MCP 2025-06-18 removed batch support.
322    /// This variant exists only to return proper errors if batches are received.
323    #[deprecated(since = "2.2.3", note = "Batching removed from MCP spec")]
324    #[allow(deprecated)] // Internal use of deprecated batch type for defensive deserialization
325    RequestBatch(JsonRpcBatch<JsonRpcRequest>),
326    /// Batch of responses (NOT SUPPORTED - defensive deserialization only)
327    ///
328    /// **Deprecated**: MCP 2025-06-18 removed batch support.
329    /// This variant exists only to return proper errors if batches are received.
330    #[deprecated(since = "2.2.3", note = "Batching removed from MCP spec")]
331    #[allow(deprecated)] // Internal use of deprecated batch type for defensive deserialization
332    ResponseBatch(JsonRpcBatch<JsonRpcResponse>),
333    /// Mixed batch (NOT SUPPORTED - defensive deserialization only)
334    ///
335    /// **Deprecated**: MCP 2025-06-18 removed batch support.
336    /// This variant exists only to return proper errors if batches are received.
337    #[deprecated(since = "2.2.3", note = "Batching removed from MCP spec")]
338    #[allow(deprecated)] // Internal use of deprecated batch type for defensive deserialization
339    MessageBatch(JsonRpcBatch<JsonRpcMessage>),
340}
341
342impl JsonRpcRequest {
343    /// Create a new JSON-RPC request
344    pub fn new(method: String, params: Option<Value>, id: RequestId) -> Self {
345        Self {
346            jsonrpc: JsonRpcVersion,
347            method,
348            params,
349            id,
350        }
351    }
352
353    /// Create a request with no parameters
354    pub fn without_params(method: String, id: RequestId) -> Self {
355        Self::new(method, None, id)
356    }
357
358    /// Create a request with parameters
359    pub fn with_params<P: Serialize>(
360        method: String,
361        params: P,
362        id: RequestId,
363    ) -> Result<Self, serde_json::Error> {
364        let params_value = serde_json::to_value(params)?;
365        Ok(Self::new(method, Some(params_value), id))
366    }
367}
368
369impl JsonRpcResponse {
370    /// Create a successful response
371    pub fn success(result: Value, id: RequestId) -> Self {
372        Self {
373            jsonrpc: JsonRpcVersion,
374            payload: JsonRpcResponsePayload::Success { result },
375            id: ResponseId::from_request(id),
376        }
377    }
378
379    /// Create an error response with request ID
380    pub fn error_response(error: JsonRpcError, id: RequestId) -> Self {
381        Self {
382            jsonrpc: JsonRpcVersion,
383            payload: JsonRpcResponsePayload::Error { error },
384            id: ResponseId::from_request(id),
385        }
386    }
387
388    /// Create a parse error response (id is null)
389    pub fn parse_error(message: Option<String>) -> Self {
390        let error = JsonRpcError {
391            code: JsonRpcErrorCode::ParseError.code(),
392            message: message.unwrap_or_else(|| JsonRpcErrorCode::ParseError.message().to_string()),
393            data: None,
394        };
395        Self {
396            jsonrpc: JsonRpcVersion,
397            payload: JsonRpcResponsePayload::Error { error },
398            id: ResponseId::null(),
399        }
400    }
401
402    /// Check if this is a successful response
403    pub fn is_success(&self) -> bool {
404        matches!(self.payload, JsonRpcResponsePayload::Success { .. })
405    }
406
407    /// Check if this is an error response
408    pub fn is_error(&self) -> bool {
409        matches!(self.payload, JsonRpcResponsePayload::Error { .. })
410    }
411
412    /// Get the result if this is a success response
413    pub fn result(&self) -> Option<&Value> {
414        match &self.payload {
415            JsonRpcResponsePayload::Success { result } => Some(result),
416            JsonRpcResponsePayload::Error { .. } => None,
417        }
418    }
419
420    /// Get the error if this is an error response
421    pub fn error(&self) -> Option<&JsonRpcError> {
422        match &self.payload {
423            JsonRpcResponsePayload::Success { .. } => None,
424            JsonRpcResponsePayload::Error { error } => Some(error),
425        }
426    }
427
428    /// Get the request ID if this is not a parse error
429    pub fn request_id(&self) -> Option<&RequestId> {
430        self.id.as_request_id()
431    }
432
433    /// Check if this response is for a parse error (has null ID)
434    pub fn is_parse_error(&self) -> bool {
435        self.id.is_null()
436    }
437
438    /// Get mutable reference to result if this is a success response
439    pub fn result_mut(&mut self) -> Option<&mut Value> {
440        match &mut self.payload {
441            JsonRpcResponsePayload::Success { result } => Some(result),
442            JsonRpcResponsePayload::Error { .. } => None,
443        }
444    }
445
446    /// Get mutable reference to error if this is an error response
447    pub fn error_mut(&mut self) -> Option<&mut JsonRpcError> {
448        match &mut self.payload {
449            JsonRpcResponsePayload::Success { .. } => None,
450            JsonRpcResponsePayload::Error { error } => Some(error),
451        }
452    }
453
454    /// Set the result for this response (converts to success response)
455    pub fn set_result(&mut self, result: Value) {
456        self.payload = JsonRpcResponsePayload::Success { result };
457    }
458
459    /// Set the error for this response (converts to error response)
460    pub fn set_error(&mut self, error: JsonRpcError) {
461        self.payload = JsonRpcResponsePayload::Error { error };
462    }
463}
464
465impl JsonRpcNotification {
466    /// Create a new JSON-RPC notification
467    pub fn new(method: String, params: Option<Value>) -> Self {
468        Self {
469            jsonrpc: JsonRpcVersion,
470            method,
471            params,
472        }
473    }
474
475    /// Create a notification with no parameters
476    pub fn without_params(method: String) -> Self {
477        Self::new(method, None)
478    }
479
480    /// Create a notification with parameters
481    pub fn with_params<P: Serialize>(method: String, params: P) -> Result<Self, serde_json::Error> {
482        let params_value = serde_json::to_value(params)?;
483        Ok(Self::new(method, Some(params_value)))
484    }
485}
486
487// Allow deprecated warnings for internal implementation of deprecated batch types
488// External users will still see deprecation warnings, but implementation won't spam warnings
489#[allow(deprecated)]
490impl<T> JsonRpcBatch<T> {
491    /// Create a new batch
492    pub fn new(items: Vec<T>) -> Self {
493        Self { items }
494    }
495
496    /// Create an empty batch
497    pub fn empty() -> Self {
498        Self::new(Vec::new())
499    }
500
501    /// Add an item to the batch
502    pub fn push(&mut self, item: T) {
503        self.items.push(item);
504    }
505
506    /// Get the number of items in the batch
507    pub fn len(&self) -> usize {
508        self.items.len()
509    }
510
511    /// Check if the batch is empty
512    pub fn is_empty(&self) -> bool {
513        self.items.is_empty()
514    }
515
516    /// Iterate over batch items
517    pub fn iter(&self) -> impl Iterator<Item = &T> {
518        self.items.iter()
519    }
520}
521
522#[allow(deprecated)]
523impl<T> IntoIterator for JsonRpcBatch<T> {
524    type Item = T;
525    type IntoIter = std::vec::IntoIter<T>;
526
527    fn into_iter(self) -> Self::IntoIter {
528        self.items.into_iter()
529    }
530}
531
532#[allow(deprecated)]
533impl<T> From<Vec<T>> for JsonRpcBatch<T> {
534    fn from(items: Vec<T>) -> Self {
535        Self::new(items)
536    }
537}
538
539/// Utility functions for JSON-RPC message handling
540pub mod utils {
541    use super::*;
542
543    /// Parse a JSON-RPC message from a string
544    pub fn parse_message(json: &str) -> Result<JsonRpcMessage, serde_json::Error> {
545        serde_json::from_str(json)
546    }
547
548    /// Serialize a JSON-RPC message to a string
549    pub fn serialize_message(message: &JsonRpcMessage) -> Result<String, serde_json::Error> {
550        serde_json::to_string(message)
551    }
552
553    /// Check if a string looks like a JSON-RPC batch
554    pub fn is_batch(json: &str) -> bool {
555        json.trim_start().starts_with('[')
556    }
557
558    /// Extract the method name from a JSON-RPC message string
559    pub fn extract_method(json: &str) -> Option<String> {
560        // Simple regex-free method extraction for performance
561        if let Ok(value) = serde_json::from_str::<serde_json::Value>(json)
562            && let Some(method) = value.get("method")
563        {
564            return method.as_str().map(String::from);
565        }
566        None
567    }
568}
569
570/// HTTP boundary types for lenient JSON-RPC parsing
571///
572/// These types are designed for parsing JSON-RPC messages at HTTP boundaries where
573/// the input may not be strictly compliant. They accept any valid JSON structure
574/// and can be converted to the canonical types after validation.
575///
576/// # Usage
577///
578/// ```rust
579/// use turbomcp_protocol::jsonrpc::http::{HttpJsonRpcRequest, HttpJsonRpcResponse};
580/// use turbomcp_protocol::jsonrpc::JsonRpcError;
581///
582/// // Parse lenient request
583/// let raw_json = r#"{"jsonrpc":"2.0","method":"test","id":1}"#;
584/// let request: HttpJsonRpcRequest = serde_json::from_str(raw_json).unwrap();
585///
586/// // Validate and use
587/// if request.jsonrpc != "2.0" {
588///     // Return error with the id we managed to extract
589/// }
590/// ```
591pub mod http {
592    use serde::{Deserialize, Serialize};
593    use serde_json::Value;
594
595    /// Lenient JSON-RPC request for HTTP boundary parsing
596    ///
597    /// This type accepts any string for `jsonrpc` and any JSON value for `id`,
598    /// allowing proper error handling when clients send non-compliant requests.
599    #[derive(Debug, Clone, Serialize, Deserialize)]
600    pub struct HttpJsonRpcRequest {
601        /// JSON-RPC version (should be "2.0" but accepts any string for error handling)
602        pub jsonrpc: String,
603        /// Request ID (can be string, number, or null)
604        #[serde(default)]
605        pub id: Option<Value>,
606        /// Method name
607        pub method: String,
608        /// Method parameters
609        #[serde(default)]
610        pub params: Option<Value>,
611    }
612
613    impl HttpJsonRpcRequest {
614        /// Check if this is a valid JSON-RPC 2.0 request
615        pub fn is_valid(&self) -> bool {
616            self.jsonrpc == "2.0" && !self.method.is_empty()
617        }
618
619        /// Check if this is a notification (no id)
620        pub fn is_notification(&self) -> bool {
621            self.id.is_none()
622        }
623
624        /// Get the id as a string if it's a string, or convert number to string
625        pub fn id_string(&self) -> Option<String> {
626            self.id.as_ref().map(|v| match v {
627                Value::String(s) => s.clone(),
628                Value::Number(n) => n.to_string(),
629                _ => v.to_string(),
630            })
631        }
632    }
633
634    /// Lenient JSON-RPC response for HTTP boundary
635    ///
636    /// Uses separate result/error fields for compatibility with various JSON-RPC
637    /// implementations.
638    #[derive(Debug, Clone, Serialize, Deserialize)]
639    pub struct HttpJsonRpcResponse {
640        /// JSON-RPC version
641        pub jsonrpc: String,
642        /// Response ID
643        #[serde(default)]
644        pub id: Option<Value>,
645        /// Success result
646        #[serde(skip_serializing_if = "Option::is_none")]
647        pub result: Option<Value>,
648        /// Error information
649        #[serde(skip_serializing_if = "Option::is_none")]
650        pub error: Option<super::JsonRpcError>,
651    }
652
653    impl HttpJsonRpcResponse {
654        /// Create a success response
655        pub fn success(id: Option<Value>, result: Value) -> Self {
656            Self {
657                jsonrpc: "2.0".to_string(),
658                id,
659                result: Some(result),
660                error: None,
661            }
662        }
663
664        /// Create an error response
665        pub fn error(id: Option<Value>, error: super::JsonRpcError) -> Self {
666            Self {
667                jsonrpc: "2.0".to_string(),
668                id,
669                result: None,
670                error: Some(error),
671            }
672        }
673
674        /// Create an error response from error code
675        pub fn error_from_code(id: Option<Value>, code: i32, message: impl Into<String>) -> Self {
676            Self::error(id, super::JsonRpcError::new(code, message))
677        }
678
679        /// Create an invalid request error response
680        pub fn invalid_request(id: Option<Value>, reason: impl Into<String>) -> Self {
681            Self::error(id, super::JsonRpcError::invalid_request_with_reason(reason))
682        }
683
684        /// Create a parse error response (id is always null for parse errors)
685        pub fn parse_error(details: Option<String>) -> Self {
686            Self::error(
687                None,
688                details
689                    .map(super::JsonRpcError::parse_error_with_details)
690                    .unwrap_or_else(super::JsonRpcError::parse_error),
691            )
692        }
693
694        /// Create an internal error response
695        pub fn internal_error(id: Option<Value>, details: &str) -> Self {
696            Self::error(id, super::JsonRpcError::internal_error(details))
697        }
698
699        /// Create a method not found error response
700        pub fn method_not_found(id: Option<Value>, method: &str) -> Self {
701            Self::error(id, super::JsonRpcError::method_not_found(method))
702        }
703
704        /// Check if this is an error response
705        pub fn is_error(&self) -> bool {
706            self.error.is_some()
707        }
708
709        /// Check if this is a success response
710        pub fn is_success(&self) -> bool {
711            self.result.is_some() && self.error.is_none()
712        }
713    }
714
715    #[cfg(test)]
716    mod tests {
717        use super::*;
718
719        #[test]
720        fn test_http_request_parsing() {
721            let json = r#"{"jsonrpc":"2.0","method":"test","id":1,"params":{"key":"value"}}"#;
722            let request: HttpJsonRpcRequest = serde_json::from_str(json).unwrap();
723            assert!(request.is_valid());
724            assert!(!request.is_notification());
725            assert_eq!(request.method, "test");
726        }
727
728        #[test]
729        fn test_http_request_invalid_version() {
730            let json = r#"{"jsonrpc":"1.0","method":"test","id":1}"#;
731            let request: HttpJsonRpcRequest = serde_json::from_str(json).unwrap();
732            assert!(!request.is_valid());
733        }
734
735        #[test]
736        fn test_http_response_success() {
737            let response = HttpJsonRpcResponse::success(
738                Some(Value::Number(1.into())),
739                serde_json::json!({"result": "ok"}),
740            );
741            assert!(response.is_success());
742            assert!(!response.is_error());
743        }
744
745        #[test]
746        fn test_http_response_error() {
747            let response = HttpJsonRpcResponse::invalid_request(
748                Some(Value::String("req-1".into())),
749                "jsonrpc must be 2.0",
750            );
751            assert!(!response.is_success());
752            assert!(response.is_error());
753        }
754
755        #[test]
756        fn test_http_response_serialization() {
757            let response = HttpJsonRpcResponse::success(
758                Some(Value::Number(1.into())),
759                serde_json::json!({"data": "test"}),
760            );
761            let json = serde_json::to_string(&response).unwrap();
762            assert!(json.contains(r#""jsonrpc":"2.0""#));
763            assert!(json.contains(r#""result""#));
764            assert!(!json.contains(r#""error""#));
765        }
766    }
767}
768
769#[cfg(test)]
770#[allow(deprecated)] // Tests cover deprecated batch functionality for defensive deserialization
771mod tests {
772    use super::*;
773    use serde_json::json;
774
775    #[test]
776    fn test_jsonrpc_version() {
777        let version = JsonRpcVersion;
778        let json = serde_json::to_string(&version).unwrap();
779        assert_eq!(json, "\"2.0\"");
780
781        let parsed: JsonRpcVersion = serde_json::from_str(&json).unwrap();
782        assert_eq!(parsed, version);
783    }
784
785    #[test]
786    fn test_request_creation() {
787        let request = JsonRpcRequest::new(
788            "test_method".to_string(),
789            Some(json!({"key": "value"})),
790            RequestId::String("test-id".to_string()),
791        );
792
793        assert_eq!(request.method, "test_method");
794        assert!(request.params.is_some());
795    }
796
797    #[test]
798    fn test_response_creation() {
799        let response = JsonRpcResponse::success(
800            json!({"result": "success"}),
801            RequestId::String("test-id".to_string()),
802        );
803
804        assert!(response.is_success());
805        assert!(!response.is_error());
806        assert!(response.result().is_some());
807        assert!(response.error().is_none());
808        assert!(!response.is_parse_error());
809    }
810
811    #[test]
812    fn test_error_response() {
813        let error = JsonRpcError::from(JsonRpcErrorCode::MethodNotFound);
814        let response =
815            JsonRpcResponse::error_response(error, RequestId::String("test-id".to_string()));
816
817        assert!(!response.is_success());
818        assert!(response.is_error());
819        assert!(response.result().is_none());
820        assert!(response.error().is_some());
821        assert!(!response.is_parse_error());
822    }
823
824    #[test]
825    fn test_parse_error_response() {
826        let response = JsonRpcResponse::parse_error(Some("Invalid JSON".to_string()));
827
828        assert!(!response.is_success());
829        assert!(response.is_error());
830        assert!(response.result().is_none());
831        assert!(response.error().is_some());
832        assert!(response.is_parse_error());
833        assert!(response.request_id().is_none());
834
835        // Verify the error details
836        let error = response.error().unwrap();
837        assert_eq!(error.code, JsonRpcErrorCode::ParseError.code());
838        assert_eq!(error.message, "Invalid JSON");
839    }
840
841    #[test]
842    fn test_notification() {
843        let notification = JsonRpcNotification::without_params("test_notification".to_string());
844        assert_eq!(notification.method, "test_notification");
845        assert!(notification.params.is_none());
846    }
847
848    #[test]
849    fn test_batch() {
850        let mut batch = JsonRpcBatch::<JsonRpcRequest>::empty();
851        assert!(batch.is_empty());
852
853        batch.push(JsonRpcRequest::without_params(
854            "method1".to_string(),
855            RequestId::String("1".to_string()),
856        ));
857        batch.push(JsonRpcRequest::without_params(
858            "method2".to_string(),
859            RequestId::String("2".to_string()),
860        ));
861
862        assert_eq!(batch.len(), 2);
863        assert!(!batch.is_empty());
864    }
865
866    #[test]
867    fn test_serialization() {
868        let request = JsonRpcRequest::new(
869            "test_method".to_string(),
870            Some(json!({"param": "value"})),
871            RequestId::String("123".to_string()),
872        );
873
874        let json = serde_json::to_string(&request).unwrap();
875        let parsed: JsonRpcRequest = serde_json::from_str(&json).unwrap();
876
877        assert_eq!(parsed.method, request.method);
878        assert_eq!(parsed.params, request.params);
879    }
880
881    #[test]
882    fn test_utils() {
883        let json = r#"{"jsonrpc":"2.0","method":"test","id":"123"}"#;
884
885        assert!(!utils::is_batch(json));
886        assert_eq!(utils::extract_method(json), Some("test".to_string()));
887
888        let batch_json = r#"[{"jsonrpc":"2.0","method":"test","id":"123"}]"#;
889        assert!(utils::is_batch(batch_json));
890    }
891
892    #[test]
893    fn test_error_codes() {
894        let parse_error = JsonRpcErrorCode::ParseError;
895        assert_eq!(parse_error.code(), -32700);
896        assert_eq!(parse_error.message(), "Parse error");
897
898        let app_error = JsonRpcErrorCode::ApplicationError(-32001);
899        assert_eq!(app_error.code(), -32001);
900    }
901}