From da2b938f297ebaa586e2f46e8ba6f9630d52a67c Mon Sep 17 00:00:00 2001 From: FabianLars Date: Wed, 14 Dec 2022 18:27:23 +0100 Subject: [PATCH 1/3] Add thiserror example to command guide --- docs/guides/features/command.md | 47 +++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/docs/guides/features/command.md b/docs/guides/features/command.md index e2f435b34a..313bb8cbae 100644 --- a/docs/guides/features/command.md +++ b/docs/guides/features/command.md @@ -100,6 +100,52 @@ invoke('my_custom_command') .catch((error) => console.error(error)) ``` +As mentioned above, everything returned from commands must implement [serde::Serialize], including errors. +This can be problematic if you're working with error types from Rust's std library or external crates as most error types do not implement it. +In simple scenarios you can use `map_err` to convert these errors to `String`s: + +```rust +#[tauri::command] +fn my_custom_command() -> Result<(), String> { + // This will return an error + std::fs::File::open("path/that/does/not/exist").map_err(|err| err.to_string())?; + // Return nothing on success + Ok(()) +} +``` + +Since this is not very idiomatic you may want to create your own error type which implements `serde::Serialize`. In the following example, we use the [thiserror] crate to help create the error type. It allows you to turn enums into error types by deriving the `thiserror::Error` trait. You can consult its documentation for more details. + +```rust +// create the error type that represents all errors possible in our program +#[derive(Debug, thiserror::Error)] +enum Error { + #[error(transparent)] + Io(#[from] std::io::Error) +} + +// we must manually implement serde::Serialize +impl serde::Serialize for Error { + fn serialize(&self, serializer: S) -> Result + where + S: serde::ser::Serializer, + { + serializer.serialize_str(self.to_string().as_ref()) + } +} + +#[tauri::command] +fn my_custom_command() -> Result<(), String> { + // This will return an error + std::fs::File::open("path/that/does/not/exist")?; + // Return nothing on success + Ok(()) +} +``` + +A custom error type has the advantage of making all possible errors explicit so readers can quickly identify what errors can happen. This saves other people (and yourself) enormous amounts of time when reviewing and refactoring code later.
+It also gives you full control over the way your error type gets serialized. In the above example, we simply returned the error message as a string, but you could assign each error a code similar to C, this way you could more easily map it to a similar looking TypeScript error enum for example. + ## Async Commands :::note @@ -257,3 +303,4 @@ invoke('my_custom_command', { [`async_runtime::spawn`]: https://docs.rs/tauri/1/tauri/async_runtime/fn.spawn.html [`serde::serialize`]: https://docs.serde.rs/serde/trait.Serialize.html [`serde::deserialize`]: https://docs.serde.rs/serde/trait.Deserialize.html +[`thiserror`]: https://github.com/dtolnay/thiserror From 88dd5af0e5f878a7d4372bff2fe64fc41efb35f6 Mon Sep 17 00:00:00 2001 From: Fabian-Lars Date: Thu, 29 Dec 2022 11:19:29 +0100 Subject: [PATCH 2/3] fix link --- docs/guides/features/command.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/features/command.md b/docs/guides/features/command.md index 313bb8cbae..5e2d2de08e 100644 --- a/docs/guides/features/command.md +++ b/docs/guides/features/command.md @@ -100,7 +100,7 @@ invoke('my_custom_command') .catch((error) => console.error(error)) ``` -As mentioned above, everything returned from commands must implement [serde::Serialize], including errors. +As mentioned above, everything returned from commands must implement [`serde::Serialize`], including errors. This can be problematic if you're working with error types from Rust's std library or external crates as most error types do not implement it. In simple scenarios you can use `map_err` to convert these errors to `String`s: From de547944f40f22ee52b8755c73fbfb04bf6d4e6e Mon Sep 17 00:00:00 2001 From: Fabian-Lars Date: Thu, 29 Dec 2022 12:57:41 +0100 Subject: [PATCH 3/3] Update docs/guides/features/command.md Co-authored-by: Jonas Kruckenberg --- docs/guides/features/command.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/features/command.md b/docs/guides/features/command.md index 5e2d2de08e..989ae4f5d1 100644 --- a/docs/guides/features/command.md +++ b/docs/guides/features/command.md @@ -135,7 +135,7 @@ impl serde::Serialize for Error { } #[tauri::command] -fn my_custom_command() -> Result<(), String> { +fn my_custom_command() -> Result<(), Error> { // This will return an error std::fs::File::open("path/that/does/not/exist")?; // Return nothing on success