1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-28 01:32:57 +01:00

Tweaks to the Handler chapter.

This commit is contained in:
memoryruins 2018-04-05 21:30:52 -04:00
parent 7f0de705a3
commit 961edfd21a

View File

@ -1,17 +1,18 @@
# Handler # Handler
A request handler can be any object that implements A request handler can be any object that implements
[*Handler trait*](../actix_web/dev/trait.Handler.html). [`Handler` trait](../actix_web/dev/trait.Handler.html).
Request handling happens in two stages. First the handler object is called.
Handler can return any object that implements Request handling happens in two stages. First the handler object is called,
[*Responder trait*](../actix_web/trait.Responder.html#foreign-impls). returning any object that implements the
Then `respond_to()` is called on the returned object. And finally [`Responder` trait](../actix_web/trait.Responder.html#foreign-impls).
result of the `respond_to()` call is converted to a `Reply` object. Then, `respond_to()` is called on the returned object, converting itself to a `Reply` or `Error`.
By default actix provides `Responder` implementations for some standard types, By default actix provides `Responder` implementations for some standard types,
like `&'static str`, `String`, etc. such as `&'static str`, `String`, etc.
For a complete list of implementations, check
[*Responder documentation*](../actix_web/trait.Responder.html#foreign-impls). > For a complete list of implementations, check
> [*Responder documentation*](../actix_web/trait.Responder.html#foreign-impls).
Examples of valid handlers: Examples of valid handlers:
@ -39,15 +40,16 @@ fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
} }
``` ```
Some notes on shared application state and handler state. If you noticed *Handler* trait is generic over *S*, which defines the application state's type.
*Handler* trait is generic over *S*, which defines application state type. So Application state is accessible from the handler with the `HttpRequest::state()` method;
application state is accessible from handler with the `HttpRequest::state()` method. however, state is accessible as a read-only reference. If you need mutable access to state,
But state is accessible as a read-only reference - if you need mutable access to state it must be implemented.
you have to implement it yourself. On other hand, handler can mutably access its own state
as the `handle` method takes a mutable reference to *self*. Beware, actix creates multiple copies > **Note**: Alternatively, the handler can mutably access its own state because the `handle` method takes
of application state and handlers, unique for each thread, so if you run your > mutable reference to *self*. **Beware**, actix creates multiple copies
application in several threads, actix will create the same amount as number of threads > of the application state and the handlers, unique for each thread. If you run your
of application state objects and handler objects. > 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: Here is an example of a handler that stores the number of processed requests:
@ -69,8 +71,8 @@ impl<S> Handler<S> for MyHandler {
# fn main() {} # fn main() {}
``` ```
This handler will work, but `self.0` will be different depending on the number of threads and 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` number of requests processed per thread. A proper implementation would use `Arc` and `AtomicUsize`.
```rust ```rust
# extern crate actix; # extern crate actix;
@ -111,14 +113,15 @@ fn main() {
} }
``` ```
Be careful with synchronization primitives like *Mutex* or *RwLock*. Actix web framework > Be careful with synchronization primitives like `Mutex` or `RwLock`. Actix web framework
handles requests asynchronously; by blocking thread execution all concurrent > handles requests asynchronously. By blocking thread execution, all concurrent
request handling processes would block. If you need to share or update some state > 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. > from multiple threads, consider using the [actix](https://actix.github.io/actix/actix/) actor system.
## Response with custom type ## Response with custom type
To return a custom type directly from a handler function, the type needs to implement the `Responder` trait. 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: Let's create a response for a custom type that serializes to an `application/json` response:
```rust ```rust
@ -171,10 +174,10 @@ fn main() {
## Async handlers ## Async handlers
There are two different types of async handlers. There are two different types of async handlers. Response objects can be generated asynchronously
or more precisely, any type that implements the [*Responder*](../actix_web/trait.Responder.html) trait.
Response objects can be generated asynchronously or more precisely, any type In this case, the handler must return a `Future` object that resolves to the *Responder* type, i.e:
that implements the [*Responder*](../actix_web/trait.Responder.html) trait. In this case the handler must return a `Future` object that resolves to the *Responder* type, i.e:
```rust ```rust
# extern crate actix_web; # extern crate actix_web;
@ -205,8 +208,8 @@ fn main() {
} }
``` ```
Or the response body can be generated asynchronously. In this case body Or the response body can be generated asynchronously. In this case, body
must implement stream trait `Stream<Item=Bytes, Error=Error>`, i.e: must implement the stream trait `Stream<Item=Bytes, Error=Error>`, i.e:
```rust ```rust
# extern crate actix_web; # extern crate actix_web;
@ -233,7 +236,7 @@ fn main() {
Both methods can be combined. (i.e Async response with streaming body) 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`. 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 In this example, the `index` handler can return an error immediately or return a
future that resolves to a `HttpResponse`. future that resolves to a `HttpResponse`.
```rust ```rust
@ -265,11 +268,11 @@ fn index(req: HttpRequest) -> Result<Box<Future<Item=HttpResponse, Error=Error>>
## Different return types (Either) ## Different return types (Either)
Sometimes you need to return different types of responses. For example Sometimes, you need to return different types of responses. For example,
you can do error check and return error and return async response otherwise. you can error check and return errors, return async responses, or any result that requires two different types.
Or any result that requires two different types.
For this case the [*Either*](../actix_web/enum.Either.html) type can be used. For this case, the [`Either`](../actix_web/enum.Either.html) type can be used.
*Either* allows combining two different responder types into a single type. `Either` allows combining two different responder types into a single type.
```rust ```rust
# extern crate actix_web; # extern crate actix_web;