1
0
mirror of https://github.com/actix/actix-website synced 2025-02-02 12:19:04 +01:00

First pass at errors section.

This commit is contained in:
Cameron Dershem 2019-06-17 13:46:21 -04:00
parent 71e6f076a4
commit f07c78a5ca
8 changed files with 124 additions and 107 deletions

View File

@ -52,22 +52,7 @@ foreign implementations for `ResponseError`.
Here's an example implementation for `ResponseError`: Here's an example implementation for `ResponseError`:
```rust {{< include-example example="errors" file="main.rs" section="response-error" >}}
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"})
}
```
`ResponseError` has a default implementation for `error_response()` that will `ResponseError` has a default implementation for `error_response()` that will
render a *500* (internal server error), and that's what will happen when the render a *500* (internal server error), and that's what will happen when the
@ -75,37 +60,7 @@ render a *500* (internal server error), and that's what will happen when the
Override `error_response()` to produce more useful results: Override `error_response()` to produce more useful results:
```rust {{< include-example example="errors" file="override_error.rs" section="override" >}}
#[macro_use] extern crate failure;
use actix_web::{App, HttpRequest, HttpResponse, http, error};
#[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(
http::StatusCode::INTERNAL_SERVER_ERROR),
MyError::BadClientData => HttpResponse::new(
http::StatusCode::BAD_REQUEST),
MyError::Timeout => HttpResponse::new(
http::StatusCode::GATEWAY_TIMEOUT),
}
}
}
fn index(req: &HttpRequest) -> Result<&'static str, MyError> {
Err(MyError::BadClientData)
}
```
# Error helpers # Error helpers
@ -114,21 +69,7 @@ specific HTTP error codes from other errors. Here we convert `MyError`, which
doesn't implement the `ResponseError` trait, to a *400* (bad request) using doesn't implement the `ResponseError` trait, to a *400* (bad request) using
`map_err`: `map_err`:
```rust {{< include-example example="errors" file="helpers.rs" section="helpers" >}}
# extern crate actix_web;
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(|e| error::ErrorBadRequest(e.name))?)
}
```
See the [API documentation for actix-web's `error` module][errorhelpers] for a See the [API documentation for actix-web's `error` module][errorhelpers] for a
full list of available error helpers. full list of available error helpers.
@ -165,27 +106,7 @@ 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 enum which encapsulates a `ValidationError` to return whenever a user sends bad
input: input:
```rust {{< include-example example="errors" file="recommend_one.rs" section="recommend-one" >}}
#[macro_use] extern crate failure;
use actix_web::{HttpResponse, http, error};
#[derive(Fail, Debug)]
enum UserError {
#[fail(display="Validation error on field: {}", field)]
ValidationError {
field: String,
}
}
impl error::ResponseError for UserError {
fn error_response(&self) -> HttpResponse {
match *self {
UserError::ValidationError { .. } => HttpResponse::new(
http::StatusCode::BAD_REQUEST),
}
}
}
```
This will behave exactly as intended because the error message defined with 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. `display` is written with the explicit intent to be read by a user.
@ -201,30 +122,7 @@ consumption.
Here's an example that maps an internal error to a user-facing `InternalError` Here's an example that maps an internal error to a user-facing `InternalError`
with a custom message: with a custom message:
```rust {{< include-example example="errors" file="recommend_two.rs" section="recommend-two" >}}
#[macro_use] extern crate failure;
use actix_web::{App, HttpRequest, HttpResponse, http, error, fs};
#[derive(Fail, Debug)]
enum UserError {
#[fail(display="An internal error occurred. Please try again later.")]
InternalError,
}
impl error::ResponseError for UserError {
fn error_response(&self) -> HttpResponse {
match *self {
UserError::InternalError => HttpResponse::new(
http::StatusCode::INTERNAL_SERVER_ERROR),
}
}
}
fn index(_: &HttpRequest) -> Result<&'static str, UserError> {
fs::NamedFile::open("static/index.html").map_err(|_e| UserError::InternalError)?;
Ok("success!")
}
```
By dividing errors into those which are user facing and those which are not, we 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 can ensure that we don't accidentally expose users to errors thrown by

View File

@ -17,4 +17,5 @@ exclude = [
"async-handlers", "async-handlers",
"extractors", "extractors",
"autoreload", "autoreload",
"errors"
] ]

View File

@ -0,0 +1,8 @@
[package]
name = "errors"
version = "0.1.0"
edition = "2018"
[dependencies]
actix-web = "1.0"
failure = "0.1"

View File

@ -0,0 +1,14 @@
// <helpers>
use actix_web::{error, HttpRequest, Result};
#[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(|e| error::ErrorBadRequest(e.name))?)
}
// </helpers>

View File

@ -0,0 +1,21 @@
mod helpers;
mod override_error;
mod recommend_one;
// <response-error>
use actix_web::{error, HttpRequest};
use failure::Fail;
#[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" })
}
// </response-error>
fn main() {}

View File

@ -0,0 +1,30 @@
// <override>
use actix_web::{error, http, HttpRequest, HttpResponse};
use failure::Fail;
#[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(http::StatusCode::INTERNAL_SERVER_ERROR)
}
MyError::BadClientData => HttpResponse::new(http::StatusCode::BAD_REQUEST),
MyError::Timeout => HttpResponse::new(http::StatusCode::GATEWAY_TIMEOUT),
}
}
}
fn index(req: &HttpRequest) -> Result<&'static str, MyError> {
Err(MyError::BadClientData)
}
// </override>

View File

@ -0,0 +1,20 @@
// <recommend-one>
use actix_web::{error, http, HttpResponse};
use failure::Fail;
#[derive(Fail, Debug)]
enum UserError {
#[fail(display = "Validation error on field: {}", field)]
ValidationError { field: String },
}
impl error::ResponseError for UserError {
fn error_response(&self) -> HttpResponse {
match *self {
UserError::ValidationError { .. } => {
HttpResponse::new(http::StatusCode::BAD_REQUEST)
}
}
}
}
// </recommend-one>

View File

@ -0,0 +1,25 @@
// <recommend-two>
use actix_web::{error, fs, http, App, HttpRequest, HttpResponse};
use failure::Fail;
#[derive(Fail, Debug)]
enum UserError {
#[fail(display = "An internal error occurred. Please try again later.")]
InternalError,
}
impl error::ResponseError for UserError {
fn error_response(&self) -> HttpResponse {
match *self {
UserError::InternalError => {
HttpResponse::new(http::StatusCode::INTERNAL_SERVER_ERROR)
}
}
}
}
fn index(_req: HttpRequest) -> Result<&'static str, UserError> {
fs::NamedFile::open("static/index.html").map_err(|_e| UserError::InternalError)?;
Ok("success!")
}
// </recommend-two>