1
0
mirror of https://github.com/actix/actix-website synced 2024-11-30 19:14:36 +01:00
actix-website/content/docs/errors.md

134 lines
5.2 KiB
Markdown
Raw Normal View History

2018-05-22 23:15:08 +02:00
---
title: Errors
menu: docs_advanced
weight: 180
---
# Errors
2019-06-25 03:18:30 +02:00
Actix-web uses its own [`actix_web::error::Error`][actixerror] type and
2020-09-12 17:21:54 +02:00
[`actix_web::error::ResponseError`][responseerror] trait for error handling from web handlers.
2018-05-22 23:15:08 +02:00
If a handler returns an `Error` (referring to the [general Rust trait
2020-09-12 17:21:54 +02:00
`std::error::Error`][stderror]) in a `Result` that also implements the `ResponseError` trait,
actix-web will render that error as an HTTP response with its corresponding
[`actix_web::http::StatusCode`][status_code]. An internal server error is generated by default:
2018-05-22 23:15:08 +02:00
```rust
pub trait ResponseError {
2020-06-26 18:36:31 +02:00
fn error_response(&self) -> Response<Body>;
fn status_code(&self) -> StatusCode;
2018-05-22 23:15:08 +02:00
}
```
A `Responder` coerces compatible `Result`s into HTTP responses:
```rust
impl<T: Responder, E: Into<Error>> Responder for Result<T, E>
```
2020-09-12 17:21:54 +02:00
`Error` in the code above is actix-web's error definition, and any errors that implement
`ResponseError` can be converted to one automatically.
2018-05-22 23:15:08 +02:00
2020-09-12 17:21:54 +02:00
Actix-web provides `ResponseError` implementations for some common non-actix errors. For example, if
a handler responds with an `io::Error`, that error is converted into an `HttpInternalServerError`:
2018-05-22 23:15:08 +02:00
```rust
use std::io;
2020-06-26 18:49:01 +02:00
use actix_files::NamedFile;
2018-05-22 23:15:08 +02:00
2020-06-26 18:49:01 +02:00
fn index(_req: HttpRequest) -> io::Result<NamedFile> {
Ok(NamedFile::open("static/index.html")?)
2018-05-22 23:15:08 +02:00
}
```
2020-09-12 17:21:54 +02:00
See [the actix-web API documentation][responseerrorimpls] for a full list of foreign implementations
for `ResponseError`.
2018-05-22 23:15:08 +02:00
## An example of a custom error response
2020-09-12 17:21:54 +02:00
Here's an example implementation for `ResponseError`, using the [derive_more] crate
for declarative error enums.
2018-05-22 23:15:08 +02:00
2019-06-17 19:46:21 +02:00
{{< include-example example="errors" file="main.rs" section="response-error" >}}
2018-05-22 23:15:08 +02:00
2020-09-12 17:21:54 +02:00
`ResponseError` has a default implementation for `error_response()` that will render a _500_
(internal server error), and that's what will happen when the `index` handler executes above.
2018-05-22 23:15:08 +02:00
Override `error_response()` to produce more useful results:
2019-06-17 19:46:21 +02:00
{{< include-example example="errors" file="override_error.rs" section="override" >}}
2018-05-22 23:15:08 +02:00
# Error helpers
2020-09-12 17:21:54 +02:00
Actix-web provides a set of error helper functions that are useful for generating specific HTTP
error codes from other errors. Here we convert `MyError`, which doesn't implement the
`ResponseError` trait, to a _400_ (bad request) using `map_err`:
2018-05-22 23:15:08 +02:00
2019-06-17 19:46:21 +02:00
{{< include-example example="errors" file="helpers.rs" section="helpers" >}}
2018-05-22 23:15:08 +02:00
2020-09-12 17:21:54 +02:00
See the [API documentation for actix-web's `error` module][actixerror] for a full list of available
error helpers.
2018-05-22 23:15:08 +02:00
# Error logging
2020-09-12 17:21:54 +02:00
Actix logs all errors at the `WARN` log level. If an application's log level is set to `DEBUG` and
`RUST_BACKTRACE` is enabled, the backtrace is also logged. These are configurable with environmental
variables:
2018-05-22 23:15:08 +02:00
```
>> RUST_BACKTRACE=1 RUST_LOG=actix_web=debug cargo run
```
2020-09-12 17:21:54 +02:00
The `Error` type uses the cause's error backtrace if available. If the underlying failure does not
provide a backtrace, a new backtrace is constructed pointing to the point where the conversion
occurred (rather than the origin of the error).
2018-05-22 23:15:08 +02:00
# Recommended practices in error handling
2020-09-12 17:21:54 +02:00
It might be useful to think about dividing the errors an application produces into two broad groups:
those which are intended to be user-facing, and those which are not.
2018-05-22 23:15:08 +02:00
2020-09-12 17:21:54 +02:00
An example of the former is that I might use failure to specify a `UserError` enum which
encapsulates a `ValidationError` to return whenever a user sends bad input:
2018-05-22 23:15:08 +02:00
2019-06-17 19:46:21 +02:00
{{< include-example example="errors" file="recommend_one.rs" section="recommend-one" >}}
2018-05-22 23:15:08 +02:00
2020-09-12 17:21:54 +02:00
This will behave exactly as intended because the error message defined with `display` is written
with the explicit intent to be read by a user.
2018-05-22 23:15:08 +02:00
2020-09-12 17:21:54 +02:00
However, sending back an error's message isn't desirable for all errors -- there are many failures
that occur in a server environment where we'd probably want the specifics to be hidden from the
user. For example, if a database goes down and client libraries start producing connect timeout
errors, or if an HTML template was improperly formatted and errors when rendered. In these cases, it
might be preferable to map the errors to a generic error suitable for user consumption.
2018-05-22 23:15:08 +02:00
2020-09-12 17:21:54 +02:00
Here's an example that maps an internal error to a user-facing `InternalError` with a custom
message:
2018-05-22 23:15:08 +02:00
2019-06-17 19:46:21 +02:00
{{< include-example example="errors" file="recommend_two.rs" section="recommend-two" >}}
2018-05-22 23:15:08 +02:00
2020-09-12 17:21:54 +02:00
By dividing errors into those which are user facing and those which are not, we can ensure that we
don't accidentally expose users to errors thrown by application internals which they weren't meant
to see.
2018-05-22 23:15:08 +02:00
# Error Logging
This is a basic example using `middleware::Logger` which depends on `env_logger` and `log`:
```toml
[dependencies]
env_logger = "0.8"
log = "0.4"
```
{{< include-example example="errors" file="logging.rs" section="logging" >}}
2020-09-12 17:21:54 +02:00
[actixerror]: https://docs.rs/actix-web/3/actix_web/error/struct.Error.html
[errorhelpers]: https://docs.rs/actix-web/3/actix_web/trait.ResponseError.html
[derive_more]: https://crates.io/crates/derive_more
[responseerror]: https://docs.rs/actix-web/3/actix_web/error/trait.ResponseError.html
[responseerrorimpls]:
https://docs.rs/actix-web/3/actix_web/error/trait.ResponseError.html#foreign-impls
2018-05-22 23:15:08 +02:00
[stderror]: https://doc.rust-lang.org/std/error/trait.Error.html
2020-09-12 17:21:54 +02:00
[status_code]: https://docs.rs/actix-web/3.0.0/actix_web/http/struct.StatusCode.html