use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
#[repr(i32)]
pub enum ErrorCode {
ParseError = -32700,
InvalidRequest = -32600,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603,
ServerNotInitialized = -32002,
UnknownErrorCode = -32001,
RequestFailed = -32803,
ServerCancelled = -32802,
ContentModified = -32801,
RequestCancelled = -32800,
}
impl From<ErrorCode> for i32 {
fn from(code: ErrorCode) -> Self {
code as i32
}
}
impl TryFrom<i32> for ErrorCode {
type Error = i32;
fn try_from(code: i32) -> Result<Self, Self::Error> {
match code {
-32700 => Ok(ErrorCode::ParseError),
-32600 => Ok(ErrorCode::InvalidRequest),
-32601 => Ok(ErrorCode::MethodNotFound),
-32602 => Ok(ErrorCode::InvalidParams),
-32603 => Ok(ErrorCode::InternalError),
-32002 => Ok(ErrorCode::ServerNotInitialized),
-32001 => Ok(ErrorCode::UnknownErrorCode),
-32803 => Ok(ErrorCode::RequestFailed),
-32802 => Ok(ErrorCode::ServerCancelled),
-32801 => Ok(ErrorCode::ContentModified),
-32800 => Ok(ErrorCode::RequestCancelled),
_ => Err(code),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResponseError {
pub code: i32,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<Value>,
}
impl ResponseError {
pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
Self {
code: code as i32,
message: message.into(),
data: None,
}
}
pub fn new_raw(code: i32, message: impl Into<String>) -> Self {
Self {
code,
message: message.into(),
data: None,
}
}
#[must_use]
pub fn with_data(mut self, data: Value) -> Self {
self.data = Some(data);
self
}
#[must_use]
pub fn error_code(&self) -> Option<ErrorCode> {
ErrorCode::try_from(self.code).ok()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn error_code_to_i32() {
assert_eq!(i32::from(ErrorCode::ParseError), -32700);
assert_eq!(i32::from(ErrorCode::InvalidRequest), -32600);
assert_eq!(i32::from(ErrorCode::MethodNotFound), -32601);
assert_eq!(i32::from(ErrorCode::InvalidParams), -32602);
assert_eq!(i32::from(ErrorCode::InternalError), -32603);
assert_eq!(i32::from(ErrorCode::ServerNotInitialized), -32002);
assert_eq!(i32::from(ErrorCode::UnknownErrorCode), -32001);
assert_eq!(i32::from(ErrorCode::RequestFailed), -32803);
assert_eq!(i32::from(ErrorCode::ServerCancelled), -32802);
assert_eq!(i32::from(ErrorCode::ContentModified), -32801);
assert_eq!(i32::from(ErrorCode::RequestCancelled), -32800);
}
#[test]
fn i32_to_error_code() {
assert_eq!(ErrorCode::try_from(-32700), Ok(ErrorCode::ParseError));
assert_eq!(ErrorCode::try_from(-32601), Ok(ErrorCode::MethodNotFound));
assert_eq!(ErrorCode::try_from(-32800), Ok(ErrorCode::RequestCancelled));
assert_eq!(ErrorCode::try_from(-99999), Err(-99999));
}
#[test]
fn response_error_construction() {
let error = ResponseError::new(ErrorCode::MethodNotFound, "Method not found");
assert_eq!(error.code, -32601);
assert_eq!(error.message, "Method not found");
assert!(error.data.is_none());
}
#[test]
fn response_error_with_data() {
let error = ResponseError::new(ErrorCode::InvalidParams, "Invalid params")
.with_data(serde_json::json!({"field": "uri"}));
assert_eq!(error.code, -32602);
assert!(error.data.is_some());
assert_eq!(error.data.unwrap()["field"], "uri");
}
#[test]
fn response_error_serialization_without_data() {
let error = ResponseError::new(ErrorCode::ParseError, "Parse error");
let json = serde_json::to_string(&error).unwrap();
assert!(!json.contains("data"));
assert!(json.contains("-32700"));
assert!(json.contains("Parse error"));
}
#[test]
fn response_error_serialization_with_data() {
let error = ResponseError::new(ErrorCode::InvalidParams, "Missing field")
.with_data(serde_json::json!({"missing": "uri"}));
let json = serde_json::to_string(&error).unwrap();
assert!(json.contains("data"));
assert!(json.contains("missing"));
}
#[test]
fn response_error_deserialization() {
let json = r#"{"code":-32601,"message":"Method not found"}"#;
let error: ResponseError = serde_json::from_str(json).unwrap();
assert_eq!(error.code, -32601);
assert_eq!(error.message, "Method not found");
assert!(error.data.is_none());
}
#[test]
fn response_error_deserialization_with_data() {
let json = r#"{"code":-32602,"message":"Invalid","data":{"field":"uri"}}"#;
let error: ResponseError = serde_json::from_str(json).unwrap();
assert_eq!(error.code, -32602);
assert!(error.data.is_some());
}
#[test]
fn response_error_raw_code() {
let error = ResponseError::new_raw(-99999, "Custom error");
assert_eq!(error.code, -99999);
assert!(error.error_code().is_none());
}
#[test]
fn skip_serializing_if_works() {
let error = ResponseError::new(ErrorCode::InternalError, "Error");
let json = serde_json::to_value(&error).unwrap();
let obj = json.as_object().unwrap();
assert!(!obj.contains_key("data"));
}
}