From 59f010461aa5f2c4d7809b174f55778089e32e18 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Thu, 20 Jun 2019 02:04:22 -0400 Subject: [PATCH] Handlers done-ish. --- content/docs/handlers.md | 55 +++++++-------------- examples/async-handlers/Cargo.toml | 4 +- examples/async-handlers/src/async_stream.rs | 18 ++++--- examples/async-handlers/src/main.rs | 31 ++++++------ examples/async-handlers/src/stream.rs | 18 ++++--- examples/either/src/main.rs | 4 +- examples/request-handlers/src/main.rs | 4 +- examples/responder-trait/src/main.rs | 7 ++- 8 files changed, 62 insertions(+), 79 deletions(-) diff --git a/content/docs/handlers.md b/content/docs/handlers.md index 2923dbe..699adf7 100644 --- a/content/docs/handlers.md +++ b/content/docs/handlers.md @@ -6,13 +6,17 @@ weight: 160 # Request Handlers -A request handler can be any object that implements -[*Handler*](../../actix-web/actix_web/dev/trait.Handler.html) trait. +A request handler is a function that accepts zero or more parameters that can be extracted +from a request (ie, +[*impl FromRequest*](https://docs.rs/actix-web/1.0.2/actix_web/trait.FromRequest.html)) +and returns a type that can be converted into an HttpResponse (ie, +[*impl Responder*](https://docs.rs/actix-web/1.0.2/actix_web/trait.Responder.html)). Request handling happens in two stages. First the handler object is called, returning any object that implements the -[*Responder*](../../actix-web/actix_web/trait.Responder.html#foreign-impls) trait. -Then, `respond_to()` is called on the returned object, converting itself to a `AsyncResult` or `Error`. +[*Responder*](https://docs.rs/actix-web/1.0.2/actix_web/trait.Responder.html) trait. +Then, `respond_to()` is called on the returned object, converting itself to a `HttpResponse` +or `Error`. By default actix provides `Responder` implementations for some standard types, such as `&'static str`, `String`, etc. @@ -29,7 +33,7 @@ fn index(req: &HttpRequest) -> &'static str { ``` ```rust -fn index(req: &HttpRequest) -> String { +fn index(req: HttpRequest) -> String { "Hello world!".to_owned() } ``` @@ -38,49 +42,24 @@ You can also change the signature to return `impl Responder` which works well if complex types are involved. ```rust -fn index(req: &HttpRequest) -> impl Responder { +fn index(req: HttpRequest) -> impl Responder { Bytes::from_static("Hello world!") } ``` -```rust,ignore -fn index(req: &HttpRequest) -> Box> { +```rust +fn index(req: HttpRequest) -> Box> { ... } ``` -*Handler* trait is generic over *S*, which defines the application state's type. -Application state is accessible from the handler with the `HttpRequest::state()` method; -however, state is accessible as a read-only reference. If you need mutable access to state, -it must be implemented. - -> **Note**: Alternatively, the handler can use interior mutably to access its own -> state. **Beware**, actix creates multiple copies -> of the application state and the handlers, unique for each thread. If you run your -> application in several threads, actix will create the same amount as number of threads -> of application state objects and handler objects. - -Here is an example of a handler that stores the number of processed requests: - -{{< include-example example="request-handlers" file="main.rs" section="main" >}} - -Although this handler will work, `self.0` will be different depending on the number of threads and -number of requests processed per thread. A proper implementation would use `Arc` and `AtomicUsize`. - -{{< include-example example="request-handlers" file="handlers_arc.rs" section="arc" >}} - -> Be careful with synchronization primitives like `Mutex` or `RwLock`. The `actix-web` framework -> handles requests asynchronously. By blocking thread execution, all concurrent -> request handling processes would block. If you need to share or update some state -> from multiple threads, consider using the [actix](https://actix.github.io/actix/actix/) actor system. - ## Response with custom type To return a custom type directly from a handler function, the type needs to implement the `Responder` trait. Let's create a response for a custom type that serializes to an `application/json` response: -{{< include-example example="responder-trait" file="main.rs" section="main" >}} +{{< include-example example="responder-trait" file="main.rs" section="responder-trait" >}} ## Async handlers @@ -89,12 +68,12 @@ or more precisely, any type that implements the [*Responder*](../../actix-web/ac 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="main" >}} +{{< 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`, i.e: -{{< include-example example="async-handlers" file="stream.rs" section="main" >}} +{{< include-example example="async-handlers" file="stream.rs" section="stream" >}} Both methods can be combined. (i.e Async response with streaming body) @@ -102,7 +81,7 @@ 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="main" >}} +{{< include-example example="async-handlers" file="async_stream.rs" section="async-stream" >}} ## Different return types (Either) @@ -112,4 +91,4 @@ you can error check and return errors, return async responses, or any result tha For this case, the [*Either*](../../actix-web/actix_web/enum.Either.html) type can be used. `Either` allows combining two different responder types into a single type. -{{< include-example example="either" file="main.rs" section="main" >}} +{{< include-example example="either" file="main.rs" section="either" >}} diff --git a/examples/async-handlers/Cargo.toml b/examples/async-handlers/Cargo.toml index 9a9e413..afdf0dc 100644 --- a/examples/async-handlers/Cargo.toml +++ b/examples/async-handlers/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "async-handlers" -version = "0.7.0" +version = "1.0.0" edition = "2018" [dependencies] -actix-web = "0.7" +actix-web = "1.0" futures = "0.1" bytes = "0.4" diff --git a/examples/async-handlers/src/async_stream.rs b/examples/async-handlers/src/async_stream.rs index 2641e21..b954cb0 100644 --- a/examples/async-handlers/src/async_stream.rs +++ b/examples/async-handlers/src/async_stream.rs @@ -1,24 +1,28 @@ fn is_error() -> bool { - true + false } -//
-use actix_web::{error, App, Error, HttpRequest, HttpResponse}; +// +use actix_web::{error, web, App, Error, HttpRequest, HttpResponse, HttpServer}; use futures::future::{result, Future}; fn index( - _req: &HttpRequest, + _req: HttpRequest, ) -> Result>, Error> { if is_error() { Err(error::ErrorBadRequest("bad request")) } else { Ok(Box::new(result(Ok(HttpResponse::Ok() .content_type("text/html") - .body(format!("Hello!")))))) + .body("Hello!"))))) } } -//
+// pub fn main() { - App::new().resource("/", |r| r.route().f(index)).finish(); + HttpServer::new(|| App::new().route("/", web::to_async(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } diff --git a/examples/async-handlers/src/main.rs b/examples/async-handlers/src/main.rs index b8c5f8f..f86d286 100644 --- a/examples/async-handlers/src/main.rs +++ b/examples/async-handlers/src/main.rs @@ -1,25 +1,22 @@ -mod async_stream; -mod stream; -//
-use actix_web::{App, AsyncResponder, Error, HttpRequest, HttpResponse}; -use futures::future::{result, Future}; +pub mod async_stream; +pub mod stream; +// +use actix_web::{web, App, Error, HttpRequest, HttpResponse}; +use futures::future::{ok, Future}; -fn index(_req: &HttpRequest) -> Box> { - result(Ok(HttpResponse::Ok() - .content_type("text/html") - .body(format!("Hello!")))) - .responder() +fn index(_req: HttpRequest) -> Box> { + Box::new(ok::<_, Error>( + HttpResponse::Ok().content_type("text/html").body("Hello!"), + )) } -fn index2(_req: &HttpRequest) -> Box> { - result(Ok("Welcome!")).responder() +fn index2(_req: HttpRequest) -> Box> { + Box::new(ok::<_, Error>("Welcome!")) } fn main() { App::new() - .resource("/async", |r| r.route().a(index)) - .resource("/", |r| r.route().a(index2)) - // .resource("/", |r| r.route().f(async_stream::index)) - .finish(); + .route("/async", web::to_async(index)) + .route("/", web::to_async(index2)); } -//
+// diff --git a/examples/async-handlers/src/stream.rs b/examples/async-handlers/src/stream.rs index da4c8a0..abcefb1 100644 --- a/examples/async-handlers/src/stream.rs +++ b/examples/async-handlers/src/stream.rs @@ -1,17 +1,21 @@ -//
-use actix_web::{App, Body, HttpRequest, HttpResponse}; +// +use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer}; use bytes::Bytes; use futures::stream::once; -fn index(_req: &HttpRequest) -> HttpResponse { - let body = once(Ok(Bytes::from_static(b"test"))); +fn index(_req: HttpRequest) -> HttpResponse { + let body = once::(Ok(Bytes::from_static(b"test"))); HttpResponse::Ok() .content_type("application/json") - .body(Body::Streaming(Box::new(body))) + .streaming(Box::new(body)) } pub fn main() { - App::new().resource("/async", |r| r.f(index)).finish(); + HttpServer::new(|| App::new().route("/async", web::to_async(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } -//
+// diff --git a/examples/either/src/main.rs b/examples/either/src/main.rs index 453239d..83e1fcf 100644 --- a/examples/either/src/main.rs +++ b/examples/either/src/main.rs @@ -1,4 +1,4 @@ -//
+// use actix_web::{web, App, Either, Error, HttpRequest, HttpResponse}; use futures::future::{ok, Future}; @@ -22,7 +22,7 @@ fn index(_req: HttpRequest) -> RegisterResult { fn main() { App::new().route("/", web::get().to(index)); } -//
+// fn is_a_variant() -> bool { true diff --git a/examples/request-handlers/src/main.rs b/examples/request-handlers/src/main.rs index 84d7aca..8756e7d 100644 --- a/examples/request-handlers/src/main.rs +++ b/examples/request-handlers/src/main.rs @@ -1,5 +1,5 @@ mod handlers_arc; -//
+// use actix_web::{dev::Handler, server, App, HttpRequest, HttpResponse}; use std::cell::Cell; @@ -22,4 +22,4 @@ fn main() { .unwrap() .run(); } -//
+// diff --git a/examples/responder-trait/src/main.rs b/examples/responder-trait/src/main.rs index e635151..869ea54 100644 --- a/examples/responder-trait/src/main.rs +++ b/examples/responder-trait/src/main.rs @@ -1,7 +1,6 @@ -//
+// use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer, Responder}; use serde::Serialize; -use serde_json; #[derive(Serialize)] struct MyObj { @@ -23,9 +22,10 @@ impl Responder for MyObj { } } -fn index(_req: HttpRequest) -> impl Responder { +fn index() -> impl Responder { MyObj { name: "user" } } +// fn main() { HttpServer::new(|| App::new().route("/", web::get().to(index))) @@ -34,4 +34,3 @@ fn main() { .run() .unwrap(); } -//