diff --git a/src/rust/client_gen.rs b/src/rust/client_gen.rs index 69c20ff..236468f 100644 --- a/src/rust/client_gen.rs +++ b/src/rust/client_gen.rs @@ -17,7 +17,7 @@ use crate::rust::lib_gen::{Module, ModuleDef, ModuleName}; use crate::rust::model_gen::RefCache; use crate::rust::printer::*; use crate::rust::types::{ - ref_or_box_schema_type, ref_or_schema_type, DataType, RustPrinter, RustResult, + ref_or_box_schema_type, ref_or_schema_type, DataType, ModelType, RustPrinter, RustResult, }; use crate::{Error, Result}; use convert_case::{Case, Casing}; @@ -672,18 +672,69 @@ fn render_errors(method_name: &str, error_kind: &ErrorKind, errors: &MethodError .reduce(|acc, e| acc + e) .unwrap_or_else(unit); + let display_cases = errors + .codes + .iter() + .map(|(code, model)| { + line( + unit() + + name.clone() + + "::Error" + + code.to_string() + + "(body) => write!(f, \"{}\", " + + render_error_body_to_string(model) + + "),", + ) + }) + .reduce(|acc, e| acc + e) + .unwrap_or_else(unit); + #[rustfmt::skip] let res = unit() + line(unit() + "#[derive(Debug)]") + - line(unit() + "pub enum " + name + " {") + + line(unit() + "pub enum " + name.clone() + " {") + indented( code_cases ) + - line(unit() + "}"); + line(unit() + "}") + + line(unit() + "impl std::fmt::Display for " + name.clone() + " {") + + indented( + line(unit() + "fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {") + + indented( + if !errors.codes.is_empty() { + line(unit() + "match self {") + + indented(display_cases) + + line(unit() + "}") + } else { line(unit() + indented(unit() + "write!(f, \"" + name + "\")")) } + ) + + line("}") + ) + + line("}"); Ok(res) } +fn render_error_body_to_string(typ: &DataType) -> RustPrinter { + match typ { + DataType::Model(ModelType { name }) if name == "ErrorBody" => unit() + r#"&body.error"#, + DataType::Model(ModelType { name }) if name == "ErrorsBody" => { + unit() + r#"body.errors.clone().join(", ")"# + } + DataType::Model(ModelType { name }) if name == "WorkerServiceErrorsBody" => { + unit() + + "match &body { WorkerServiceErrorsBody::Messages(" + + rust_name("crate::model", "ErrorsBody") + + " { errors }) => { errors.join(\", \") }, WorkerServiceErrorsBody::Validation(" + + rust_name("crate::model", "ErrorsBody") + + " { errors }) => { errors.join(\", \") }}" + } + DataType::Model(ModelType { name }) if name == "GolemErrorBody" => { + unit() + r#"format!("{}", body.golem_error)"# + } + _ => unit() + r#"format!("{body:?}")"#, + } +} + fn async_annotation() -> RustPrinter { unit() + "#[" + rust_name("async_trait", "async_trait") + "]" } diff --git a/src/rust/error_gen.rs b/src/rust/error_gen.rs index 087d73f..54fde76 100644 --- a/src/rust/error_gen.rs +++ b/src/rust/error_gen.rs @@ -19,12 +19,17 @@ pub fn error_gen() -> Module { let code = indoc! { r#" use bytes::Bytes; - #[derive(Debug)] + #[derive(Debug, thiserror::Error)] pub enum Error { + #[error("{0}")] Item(T), + #[error("Client error: {0}")] Reqwest(reqwest::Error), + #[error("Invalid header value: {0}")] ReqwestHeader(reqwest::header::InvalidHeaderValue), + #[error("Deserialization error: {0}")] Serde(serde_json::Error), + #[error("Unexpected response - status {code}, data: {body}", body = "String::from_utf8_lossy(data.as_ref())")] Unexpected { code: u16, data: Bytes, diff --git a/src/toml/cargo.rs b/src/toml/cargo.rs index b5b9e74..0948ccc 100644 --- a/src/toml/cargo.rs +++ b/src/toml/cargo.rs @@ -29,15 +29,16 @@ pub fn gen(name: &str, version: &str) -> String { NewLine + "[dependencies]" + NewLine + r#"async-trait = "^0.1""# + NewLine + - r#"bytes = "^1.5""# + NewLine + + r#"bytes = "^1.10""# + NewLine + r#"chrono = { version = "^0.4", features = ["serde"] }"# + NewLine + r#"futures-core = "^0.3""# + NewLine + r#"http = "^1.0""# + NewLine + - r#"reqwest = { version = "^0.11", features = ["gzip", "json", "multipart", "stream"] }"# + NewLine + + r#"reqwest = { version = "^0.12", features = ["gzip", "json", "multipart", "stream"] }"# + NewLine + r#"serde = { version = "^1.0", features = ["derive"] }"# + NewLine + r#"serde_json = "^1.0""# + NewLine + + r#"thiserror = "^2"# + NewLine + r#"tracing = "^0.1""# + NewLine + - r#"uuid = { version = "^1.6", features = ["serde"] }"# + NewLine; + r#"uuid = { version = "^1.15", features = ["serde"] }"# + NewLine; StringContext::new().print_to_string(code) }