Rust's error handling differs from languages like Java—it doesn't have constructs like try...catch
. The conventional approach is to define a global error handling type at the application level:
Here, the thiserror
crate is used, which conveniently helps define custom error types and simplifies code. For brevity, an AppResult
type is also defined.
In Rust's error handling ecosystem, two commonly used crates are thiserror
and anyhow
:
thiserror: Suitable for library developers to define clear error types. It uses derive macros to help implement the std::error::Error
trait for custom error types while allowing customization of error display. When building a library or needing to provide users with well-defined error types, thiserror
is the better choice.
anyhow: Designed for application developers, providing a generic error type anyhow::Error
that can encapsulate any error implementing the std::error::Error
trait. It focuses more on error propagation rather than definition, making it ideal for application-layer code. It allows quick conversion of various errors into anyhow::Error
, reducing boilerplate.
In some scenarios, you might use both crates: thiserror
for defining error types in libraries and anyhow
for handling and propagating those errors in applications.
In Salvo, Handler
s often encounter various errors, such as database connection failures, file access issues, or network errors. For these cases, the aforementioned error handling approach can be applied:
Here, home
directly returns an AppResult<()>
. But how should this error be displayed? We need to implement the Writer
trait for the custom AppResult
error type, where we can define error presentation:
In Salvo, a Handler
can return a Result
as long as both the Ok
and Err
variants implement the Writer
trait.
Given the widespread use of anyhow, Salvo provides built-in support for anyhow::Error
. When the anyhow
feature is enabled, anyhow::Error
implements the Writer
trait and is mapped to InternalServerError
:
To use the anyhow feature, enable it in Cargo.toml:
This allows your handler functions to directly return anyhow::Result<T>
:
Errors often contain sensitive information that shouldn't be exposed to regular users—doing so would be insecure and a privacy breach. However, developers or administrators might prefer seeing raw error details for debugging.
Since the write
method provides access to Request
and Depot
references, implementing conditional error display becomes straightforward:
Salvo's built-in error pages suffice for most cases, rendering Html, Json, or Xml based on the request's data type. However, there may be scenarios where custom error page displays are desired.
This can be achieved by implementing a custom Catcher
. For detailed instructions, refer to the Catcher
section.