Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add error handling snippets #474

Merged
merged 8 commits into from
Oct 26, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions documentation/docs/error-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,42 @@ There are recommended practices for managing errors in real-world applications.

## 🌪️ No Panicking

We recommend that you _not_ write panicking code at all, since Rust has the idiomatic `Result<T, E>`. Additionally, Rust _cannot_ catch panics on the web platform (`wasm32-unknown-unknown`), which can cause callers to wait indefinitely.
We recommend that you _not_ write panicking code at all, since Rust has the idiomatic `Result<T, E>`. Additionally, Rust _cannot_ catch panics on the web platform (`wasm32-unknown-unknown`), which can cause callers to wait forever.

```rust title="Rust"
fn not_good() {
let option = get_option();
let value_a = option.unwrap(); // This code can panic
let result = get_result();
let value_b = result.expect("This code can panic");
}

fn good() -> Result<(), SomeError> {
let option = get_option();
let value_a = option?;
let result = get_result();
let value_b = result?;
}
```

As the Rust documentation states, [most errors aren't serious enough](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html) to require the program or task to stop entirely.

## 🌈 Flexible Error Type

To manage Rust errors effectively, using a flexible error type is beneficial.

Developing an app differs from creating a library, as an app may encounter a wide range of error situations. Declaring distinct error types for hundreds of potential failures can be overwhelming. Therefore, it is advisable to utilize a single, flexible error type.
Developing an app differs from creating a library, as an app may encounter a wide range of error situations. Declaring a distinct error type for each potential failure can be overwhelming, unless the error cases are simple enough.

You can define your own custom error type or simply use one from `crates.io`:
Therefore, it is advisable to utilize a single, flexible error type. You can define your own or simply use one from `crates.io`:

- [anyhow](https://crates.io/crates/anyhow)

```rust
use anyhow::Result;

fn get_cluster_info() -> Result<ClusterMap> {
// `anyhow::Error` can be created from any error type.
// By using the `?` operator, the conversion happens automatically.
let config = std::fs::read_to_string("cluster.json")?;
let map: ClusterMap = serde_json::from_str(&config)?;
Ok(map)
Expand Down Expand Up @@ -76,20 +96,20 @@ async fn make_http_request() -> Result<MyResponse> {
// It can be any kind of failable function.
}

async fn do_work() -> Result<()> {
async fn top_level() -> Result<()> {
let my_response = make_http_request().await?;
// Do something with `my_response`.
// Additional processing may be written here.
Ok(())
}

async fn main_task() {
let result = do_work().await;
let result = top_level().await;
result.report();
}
```

This is how to use a top-level async function to report the propagated error. You will almost always use the `.report()` method because Rust automatically warns you about unused `Result`s.
This is how to use a top-level function to report the propagated error. You will almost always use the `.report()` method because Rust automatically warns you about unused `Result`s.

## 🧾 Logging

Expand Down