mirror of
https://github.com/actix/actix-website
synced 2025-02-02 04:09:06 +01:00
First pass at errors section.
This commit is contained in:
parent
71e6f076a4
commit
f07c78a5ca
@ -52,22 +52,7 @@ foreign implementations for `ResponseError`.
|
||||
|
||||
Here's an example implementation for `ResponseError`:
|
||||
|
||||
```rust
|
||||
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"})
|
||||
}
|
||||
```
|
||||
{{< include-example example="errors" file="main.rs" section="response-error" >}}
|
||||
|
||||
`ResponseError` has a default implementation for `error_response()` that will
|
||||
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:
|
||||
|
||||
```rust
|
||||
#[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)
|
||||
}
|
||||
```
|
||||
{{< include-example example="errors" file="override_error.rs" section="override" >}}
|
||||
|
||||
# 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
|
||||
`map_err`:
|
||||
|
||||
```rust
|
||||
# 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))?)
|
||||
}
|
||||
```
|
||||
{{< include-example example="errors" file="helpers.rs" section="helpers" >}}
|
||||
|
||||
See the [API documentation for actix-web's `error` module][errorhelpers] for a
|
||||
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
|
||||
input:
|
||||
|
||||
```rust
|
||||
#[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),
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
{{< include-example example="errors" file="recommend_one.rs" section="recommend-one" >}}
|
||||
|
||||
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.
|
||||
@ -201,30 +122,7 @@ consumption.
|
||||
Here's an example that maps an internal error to a user-facing `InternalError`
|
||||
with a custom message:
|
||||
|
||||
```rust
|
||||
#[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!")
|
||||
}
|
||||
```
|
||||
{{< include-example example="errors" file="recommend_two.rs" section="recommend-two" >}}
|
||||
|
||||
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
|
||||
|
@ -17,4 +17,5 @@ exclude = [
|
||||
"async-handlers",
|
||||
"extractors",
|
||||
"autoreload",
|
||||
"errors"
|
||||
]
|
||||
|
8
examples/errors/Cargo.toml
Normal file
8
examples/errors/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "errors"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
actix-web = "1.0"
|
||||
failure = "0.1"
|
14
examples/errors/src/helpers.rs
Normal file
14
examples/errors/src/helpers.rs
Normal 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>
|
21
examples/errors/src/main.rs
Normal file
21
examples/errors/src/main.rs
Normal 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() {}
|
30
examples/errors/src/override_error.rs
Normal file
30
examples/errors/src/override_error.rs
Normal 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>
|
20
examples/errors/src/recommend_one.rs
Normal file
20
examples/errors/src/recommend_one.rs
Normal 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>
|
25
examples/errors/src/recommend_two.rs
Normal file
25
examples/errors/src/recommend_two.rs
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user