1
0
mirror of https://github.com/actix/actix-website synced 2025-01-22 16:15:56 +01:00

review handlers section

This commit is contained in:
Nikolay Kim 2020-01-02 13:11:12 +06:00
parent e30c20016e
commit 4046b0b697
6 changed files with 28 additions and 104 deletions

View File

@ -6,12 +6,12 @@ weight: 160
# Request Handlers # Request Handlers
A request handler is a function that accepts zero or more parameters that can be extracted A request handler is an async function that accepts zero or more parameters that can be extracted
from a request (ie, [*impl FromRequest*][implfromrequest]) and returns a type that can from a request (ie, [*impl FromRequest*][implfromrequest]) and returns a type that can
be converted into an HttpResponse (ie, [*impl Responder*][implresponder]). be converted into an HttpResponse (ie, [*impl Responder*][implresponder]).
Request handling happens in two stages. First the handler object is called, returning any Request handling happens in two stages. First the handler object is called, returning any
object that implements the [*Responder*][respondertrait] trait. Then, `respond_to()` is object that implements the [*Responder*][respondertrait] trait. Then, `respond_to()` is
called on the returned object, converting itself to a `HttpResponse` or `Error`. called on the returned object, converting itself to a `HttpResponse` or `Error`.
By default actix-web provides `Responder` implementations for some standard types, By default actix-web provides `Responder` implementations for some standard types,
@ -22,13 +22,13 @@ such as `&'static str`, `String`, etc.
Examples of valid handlers: Examples of valid handlers:
```rust ```rust
fn index(_req: HttpRequest) -> &'static str { async fn index(_req: HttpRequest) -> &'static str {
"Hello world!" "Hello world!"
} }
``` ```
```rust ```rust
fn index(_req: HttpRequest) -> String { async fn index(_req: HttpRequest) -> String {
"Hello world!".to_owned() "Hello world!".to_owned()
} }
``` ```
@ -37,13 +37,13 @@ You can also change the signature to return `impl Responder` which works well if
complex types are involved. complex types are involved.
```rust ```rust
fn index(_req: HttpRequest) -> impl Responder { async fn index(_req: HttpRequest) -> impl Responder {
Bytes::from_static(b"Hello world!") Bytes::from_static(b"Hello world!")
} }
``` ```
```rust ```rust
fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> { async fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
... ...
} }
``` ```
@ -56,28 +56,13 @@ Let's create a response for a custom type that serializes to an `application/jso
{{< include-example example="responder-trait" file="main.rs" section="responder-trait" >}} {{< include-example example="responder-trait" file="main.rs" section="responder-trait" >}}
## Async handlers ## Streaming response body
There are two different types of async handlers. Response objects can be generated asynchronously Response body can be generated asynchronously. In this case, body must implement
or more precisely, any type that implements the [*Responder*][respondertrait] trait.
In this case, the handler must return a `Future` object that resolves to the *Responder* type, i.e:
{{< include-example example="async-handlers" file="main.rs" section="async-responder" >}}
Or the response body can be generated asynchronously. In this case, body must implement
the stream trait `Stream<Item=Bytes, Error=Error>`, i.e: the stream trait `Stream<Item=Bytes, Error=Error>`, i.e:
{{< include-example example="async-handlers" file="stream.rs" section="stream" >}} {{< include-example example="async-handlers" file="stream.rs" section="stream" >}}
Both methods can be combined. (i.e Async response with streaming body)
It is possible to return a `Result` where the `Result::Item` type can be `Future`. In
this example, the `index` handler can return an error immediately or return a future
that resolves to a `HttpResponse`.
{{< include-example example="async-handlers" file="async_stream.rs" section="async-stream" >}}
## Different return types (Either) ## Different return types (Either)
Sometimes, you need to return different types of responses. For example, you can error Sometimes, you need to return different types of responses. For example, you can error

View File

@ -1,9 +1,10 @@
[package] [package]
name = "async-handlers" name = "async-handlers"
version = "1.0.0" version = "2.0.0"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
actix-web = "1.0" actix-web = "2.0"
futures = "0.1" actix-rt = "1.0"
bytes = "0.4" futures = "0.3.1"
bytes = "0.5"

View File

@ -1,28 +0,0 @@
fn is_error() -> bool {
false
}
// <async-stream>
use actix_web::{error, Error, HttpResponse};
use futures::future::{result, Future};
fn index() -> Result<Box<dyn Future<Item = HttpResponse, Error = Error>>, Error> {
if is_error() {
Err(error::ErrorBadRequest("bad request"))
} else {
Ok(Box::new(result(Ok(HttpResponse::Ok()
.content_type("text/html")
.body("Hello!")))))
}
}
// </async-stream>
pub fn main() {
use actix_web::{web, App, HttpServer};
HttpServer::new(|| App::new().route("/", web::to_async(index)))
.bind("127.0.0.1:8088")
.unwrap()
.run()
.unwrap();
}

View File

@ -1,30 +1,3 @@
pub mod async_stream;
pub mod stream; pub mod stream;
// <async-responder>
use actix_web::{Error, HttpResponse};
use futures::future::{ok, Future};
fn index() -> Box<dyn Future<Item = HttpResponse, Error = Error>> { fn main() {}
Box::new(ok::<_, Error>(
HttpResponse::Ok().content_type("text/html").body("Hello!"),
))
}
fn index2() -> Box<dyn Future<Item = &'static str, Error = Error>> {
Box::new(ok::<_, Error>("Welcome!"))
}
fn main() {
use actix_web::{web, App, HttpServer};
HttpServer::new(|| {
App::new()
.route("/async", web::to_async(index))
.route("/", web::to_async(index2))
})
.bind("127.0.0.1:8088")
.unwrap()
.run()
.unwrap();
}
// </async-responder>

View File

@ -1,23 +1,22 @@
// <stream> // <stream>
use actix_web::{Error, HttpResponse}; use actix_web::{web, App, HttpServer, Error, HttpResponse};
use bytes::Bytes; use bytes::Bytes;
use futures::stream::once; use futures::stream::once;
use futures::future::ok;
fn index() -> HttpResponse { async fn index() -> HttpResponse {
let body = once::<Bytes, Error>(Ok(Bytes::from_static(b"test"))); let body = once(ok::<_, Error>(Bytes::from_static(b"test")));
HttpResponse::Ok() HttpResponse::Ok()
.content_type("application/json") .content_type("application/json")
.streaming(Box::new(body)) .streaming(body)
} }
pub fn main() { #[actix_rt::main]
use actix_web::{web, App, HttpServer}; async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().route("/async", web::to(index)))
HttpServer::new(|| App::new().route("/async", web::to_async(index))) .bind("127.0.0.1:8088")?
.bind("127.0.0.1:8088")
.unwrap()
.run() .run()
.unwrap(); .await
} }
// </stream> // </stream>

View File

@ -1,23 +1,18 @@
// <either> // <either>
use actix_web::{Either, Error, HttpResponse}; use actix_web::{Either, Error, HttpResponse};
use futures::future::{ok, Future};
type RegisterResult = type RegisterResult = Either<HttpResponse, Result<&'static str, Error>>;
Either<HttpResponse, Box<dyn Future<Item = HttpResponse, Error = Error>>>;
fn index() -> RegisterResult { fn index() -> RegisterResult {
if is_a_variant() { if is_a_variant() {
// <- choose variant A // <- choose variant A
Either::A(HttpResponse::BadRequest().body("Bad data")) Either::A(HttpResponse::BadRequest().body("Bad data"))
} else { } else {
Either::B( // <- variant B
// <- variant B Either::B(Ok("Hello!"))
Box::new(ok(HttpResponse::Ok()
.content_type("text/html")
.body("Hello!".to_string()))),
)
} }
} }
// </either>
fn main() { fn main() {
use actix_web::{web, App, HttpServer}; use actix_web::{web, App, HttpServer};
@ -28,7 +23,6 @@ fn main() {
.run() .run()
.unwrap(); .unwrap();
} }
// </either>
fn is_a_variant() -> bool { fn is_a_variant() -> bool {
true true