4.2 KiB
Errors
Actix uses Error
type
and ResponseError
trait
for handling handler's errors.
Any error that implements ResponseError
trait can be returned as error value.
Handler can return Result object, actix by default provides
Responder
implementation for compatible result object. Here is implementation
definition:
impl<T: Responder, E: Into<Error>> Responder for Result<T, E>
And any error that implements ResponseError
can be converted into Error
object.
For example if handler function returns io::Error
, it would be converted
into HttpInternalServerError
response. Implementation for io::Error
is provided
by default.
# extern crate actix_web;
# use actix_web::*;
use std::io;
fn index(req: HttpRequest) -> io::Result<fs::NamedFile> {
Ok(fs::NamedFile::open("static/index.html")?)
}
#
# fn main() {
# Application::new()
# .resource(r"/a/index.html", |r| r.f(index))
# .finish();
# }
Custom error response
To add support for custom errors, all we need to do is just implement ResponseError
trait
for custom error. ResponseError
trait has default implementation
for error_response()
method, it generates 500 response.
# extern crate actix_web;
#[macro_use] extern crate failure;
use actix_web::*;
#[derive(Fail, Debug)]
#[fail(display="my error")]
struct MyError {
name: &'static str
}
/// Use default implementation for `error_response()` method
impl error::ResponseError for MyError {}
fn index(req: HttpRequest) -> Result<&'static str, MyError> {
Err(MyError{name: "test"})
}
#
# fn main() {
# Application::new()
# .resource(r"/a/index.html", |r| r.f(index))
# .finish();
# }
In this example index handler will always return 500 response. But it is easy to return different responses for different type of errors.
# extern crate actix_web;
#[macro_use] extern crate failure;
use actix_web::*;
#[derive(Fail, Debug)]
enum MyError {
#[fail(display="internal error")]
InternalError,
#[fail(display="bad request")]
BadClientData,
#[fail(display="timeout")]
Timeout,
}
impl error::ResponseError for MyError {
fn error_response(&self) -> HttpResponse {
match *self {
MyError::InternalError => HttpResponse::new(
StatusCode::INTERNAL_SERVER_ERROR, Body::Empty),
MyError::BadClientData => HttpResponse::new(
StatusCode::BAD_REQUEST, Body::Empty),
MyError::Timeout => HttpResponse::new(
StatusCode::GATEWAY_TIMEOUT, Body::Empty),
}
}
}
fn index(req: HttpRequest) -> Result<&'static str, MyError> {
Err(MyError::BadClientData)
}
#
# fn main() {
# Application::new()
# .resource(r"/a/index.html", |r| r.f(index))
# .finish();
# }
Error helpers
Actix provides set of error helper types. It is possible to use them to generate specific error response. We can use helper types for first example with custom error.
# extern crate actix_web;
#[macro_use] extern crate failure;
use actix_web::*;
#[derive(Debug)]
struct MyError {
name: &'static str
}
fn index(req: HttpRequest) -> Result<&'static str> {
let result: Result<&'static str, MyError> = Err(MyError{name: "test"});
Ok(result.map_err(error::ErrorBadRequest)?)
}
# fn main() {
# Application::new()
# .resource(r"/a/index.html", |r| r.f(index))
# .finish();
# }
In this example BAD REQUEST response get generated for MyError
error.
Error logging
Actix logs all errors with WARN
log level. If log level set to DEBUG
and RUST_BACKTRACE
is enabled, backtrace get logged. The Error type uses
cause's error backtrace if available, if the underlying failure does not provide
a backtrace, a new backtrace is constructed pointing to that conversion point
(rather than the origin of the error). This construction only happens if there
is no underlying backtrace; if it does have a backtrace no new backtrace is constructed.
You can enable backtrace and debug logging with following command:
>> RUST_BACKTRACE=1 RUST_LOG=actix_web=debug cargo run