1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-28 09:42:40 +01:00
actix-extras/guide/src/qs_4.md

283 lines
8.1 KiB
Markdown
Raw Normal View History

2017-12-02 08:42:21 +01:00
# Handler
2017-12-26 20:19:08 +01:00
A request handler can by any object that implements
[*Handler trait*](../actix_web/dev/trait.Handler.html).
2017-12-09 00:25:37 +01:00
Request handling happen in two stages. First handler object get called.
Handle can return any object that implements
2017-12-14 18:43:42 +01:00
[*Responder trait*](../actix_web/trait.Responder.html#foreign-impls).
Then `respond_to()` get called on returned object. And finally
result of the `respond_to()` call get converted to `Reply` object.
2017-12-09 00:25:37 +01:00
2017-12-14 18:43:42 +01:00
By default actix provides `Responder` implementations for some standard types,
2017-12-02 08:42:21 +01:00
like `&'static str`, `String`, etc.
For complete list of implementations check
2017-12-26 20:19:08 +01:00
[*Responder documentation*](../actix_web/trait.Responder.html#foreign-impls).
2017-12-02 08:42:21 +01:00
2017-12-09 00:25:37 +01:00
Examples of valid handlers:
2017-12-02 08:42:21 +01:00
```rust,ignore
fn index(req: HttpRequest) -> &'static str {
"Hello world!"
}
```
```rust,ignore
fn index(req: HttpRequest) -> String {
"Hello world!".to_owned()
}
```
```rust,ignore
fn index(req: HttpRequest) -> Bytes {
Bytes::from_static("Hello world!")
}
```
```rust,ignore
fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
...
}
```
2017-12-26 18:00:45 +01:00
Some notes on shared application state and handler state. If you noticed
*Handler* trait is generic over *S*, which defines application state type. So
application state is accessible from handler with `HttpRequest::state()` method.
But state is accessible as a read-only reference, if you need mutable access to state
you have to implement it yourself. On other hand handler can mutable access it's own state
as `handle` method takes mutable reference to *self*. Beware, actix creates multiple copies
of application state and handlers, unique for each thread, so if you run your
application in several threads actix will create same amount as number of threads
of application state objects and handler objects.
Here is example of handler that stores number of processed requests:
```rust
# extern crate actix;
# extern crate actix_web;
use actix_web::*;
use actix_web::dev::Handler;
struct MyHandler(usize);
impl<S> Handler<S> for MyHandler {
type Result = HttpResponse;
/// Handle request
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
self.0 += 1;
2018-03-02 04:12:59 +01:00
httpcodes::HttpOk.into()
2017-12-26 18:00:45 +01:00
}
}
# fn main() {}
```
This handler will work, but `self.0` value will be different depends on number of threads and
number of requests processed per thread. Proper implementation would use `Arc` and `AtomicUsize`
```rust
# extern crate actix;
# extern crate actix_web;
use actix_web::*;
2017-12-26 18:28:24 +01:00
use actix_web::dev::Handler;
2017-12-26 18:00:45 +01:00
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
struct MyHandler(Arc<AtomicUsize>);
impl<S> Handler<S> for MyHandler {
type Result = HttpResponse;
/// Handle request
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
self.0.fetch_add(1, Ordering::Relaxed);
2018-03-02 04:12:59 +01:00
httpcodes::HttpOk.into()
2017-12-26 18:00:45 +01:00
}
}
fn main() {
let sys = actix::System::new("example");
let inc = Arc::new(AtomicUsize::new(0));
HttpServer::new(
move || {
let cloned = inc.clone();
Application::new()
2018-01-01 02:26:32 +01:00
.resource("/", move |r| r.h(MyHandler(cloned)))
2017-12-26 18:00:45 +01:00
})
.bind("127.0.0.1:8088").unwrap()
.start();
println!("Started http server: 127.0.0.1:8088");
2018-02-13 07:56:47 +01:00
# actix::Arbiter::system().do_send(actix::msgs::SystemExit(0));
2017-12-26 18:00:45 +01:00
let _ = sys.run();
}
```
2017-12-26 20:19:08 +01:00
Be careful with synchronization primitives like *Mutex* or *RwLock*. Actix web framework
handles request 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 [actix](https://actix.github.io/actix/actix/) actor system.
2017-12-09 00:25:37 +01:00
## Response with custom type
2017-12-02 08:42:21 +01:00
2017-12-27 06:07:51 +01:00
To return custom type directly from handler function, type needs to implement `Responder` trait.
2017-12-15 05:12:28 +01:00
Let's create response for custom type that serializes to `application/json` response:
2017-12-02 08:42:21 +01:00
```rust
2017-12-06 20:00:39 +01:00
# extern crate actix;
# extern crate actix_web;
2017-12-02 08:42:21 +01:00
extern crate serde;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
use actix_web::*;
#[derive(Serialize)]
struct MyObj {
2017-12-09 00:25:37 +01:00
name: &'static str,
2017-12-02 08:42:21 +01:00
}
2017-12-21 08:27:30 +01:00
/// Responder
2017-12-14 18:43:42 +01:00
impl Responder for MyObj {
type Item = HttpResponse;
type Error = Error;
2017-12-14 18:43:42 +01:00
fn respond_to(self, req: HttpRequest) -> Result<HttpResponse> {
let body = serde_json::to_string(&self)?;
2017-12-02 08:42:21 +01:00
// Create response and set content type
Ok(HttpResponse::Ok()
2017-12-02 08:42:21 +01:00
.content_type("application/json")
.body(body)?)
2017-12-02 08:42:21 +01:00
}
}
2017-12-21 08:27:30 +01:00
/// Because `MyObj` implements `Responder`, it is possible to return it directly
2017-12-09 00:25:37 +01:00
fn index(req: HttpRequest) -> MyObj {
MyObj{name: "user"}
}
2017-12-02 08:42:21 +01:00
fn main() {
let sys = actix::System::new("example");
HttpServer::new(
|| Application::new()
2017-12-09 00:25:37 +01:00
.resource("/", |r| r.method(Method::GET).f(index)))
2017-12-17 21:35:04 +01:00
.bind("127.0.0.1:8088").unwrap()
.start();
2017-12-02 08:42:21 +01:00
println!("Started http server: 127.0.0.1:8088");
2018-02-13 07:56:47 +01:00
# actix::Arbiter::system().do_send(actix::msgs::SystemExit(0));
2017-12-02 08:42:21 +01:00
let _ = sys.run();
}
```
## Async handlers
There are two different types of async handlers.
2017-12-20 21:51:39 +01:00
Response object could be generated asynchronously or more precisely, any type
that implements [*Responder*](../actix_web/trait.Responder.html) trait. In this case handle must
return `Future` object that resolves to *Responder* type, i.e:
2017-12-02 08:42:21 +01:00
2017-12-05 01:09:22 +01:00
```rust
# extern crate actix_web;
# extern crate futures;
# extern crate bytes;
# use actix_web::*;
# use bytes::Bytes;
# use futures::stream::once;
# use futures::future::{FutureResult, result};
fn index(req: HttpRequest) -> FutureResult<HttpResponse, Error> {
result(HttpResponse::Ok()
.content_type("text/html")
.body(format!("Hello!"))
.map_err(|e| e.into()))
2017-12-02 08:42:21 +01:00
}
2017-12-20 21:51:39 +01:00
fn index2(req: HttpRequest) -> FutureResult<&'static str, Error> {
result(Ok("Welcome!"))
}
2017-12-05 01:09:22 +01:00
fn main() {
Application::new()
.resource("/async", |r| r.route().a(index))
2017-12-20 21:51:39 +01:00
.resource("/", |r| r.route().a(index2))
2017-12-05 01:09:22 +01:00
.finish();
}
```
2017-12-02 08:42:21 +01:00
Or response body can be generated asynchronously. In this case body
must implement stream trait `Stream<Item=Bytes, Error=Error>`, i.e:
2017-12-05 01:09:22 +01:00
```rust
# extern crate actix_web;
# extern crate futures;
# extern crate bytes;
# use actix_web::*;
# use bytes::Bytes;
# use futures::stream::once;
2017-12-02 08:42:21 +01:00
fn index(req: HttpRequest) -> HttpResponse {
2017-12-05 01:09:22 +01:00
let body = once(Ok(Bytes::from_static(b"test")));
2017-12-02 08:42:21 +01:00
2017-12-05 01:09:22 +01:00
HttpResponse::Ok()
2017-12-02 08:42:21 +01:00
.content_type("application/json")
2017-12-05 01:09:22 +01:00
.body(Body::Streaming(Box::new(body))).unwrap()
2017-12-02 08:42:21 +01:00
}
fn main() {
Application::new()
.resource("/async", |r| r.f(index))
2017-12-02 08:42:21 +01:00
.finish();
}
```
Both methods could be combined. (i.e Async response with streaming body)
2018-01-23 05:10:05 +01:00
2018-03-10 19:12:44 +01:00
## Different return types (Either)
Sometimes you need to return different types of responses. For example
you can do error check and return error, otherwise return async response.
Or any result that requires two different types.
For this case [*Either*](../actix_web/enum.Either.html) type can be used.
```rust
# extern crate actix_web;
# extern crate futures;
# use actix_web::*;
# use futures::future::Future;
use futures::future::result;
use actix_web::{Either, Error, HttpResponse, httpcodes};
type RegisterResult = Either<HttpResponse, Box<Future<Item=HttpResponse, Error=Error>>>;
fn index(req: HttpRequest) -> RegisterResult {
2018-03-11 17:28:22 +01:00
if is_a_variant() { // <- choose variant A
2018-03-10 19:12:44 +01:00
Either::A(
httpcodes::HttpBadRequest.with_body("Bad data"))
} else {
2018-03-11 17:28:22 +01:00
Either::B( // <- variant B
2018-03-10 19:12:44 +01:00
result(HttpResponse::Ok()
.content_type("text/html")
.body(format!("Hello!"))
.map_err(|e| e.into())).responder())
}
}
2018-03-11 17:28:22 +01:00
# fn is_a_variant() -> bool { true }
# fn main() {
# Application::new()
# .resource("/register", |r| r.f(index))
# .finish();
# }
2018-03-10 19:12:44 +01:00
```
2018-01-23 05:10:05 +01:00
## Tokio core handle
Any actix web handler runs within properly configured
[actix system](https://actix.github.io/actix/actix/struct.System.html)
and [arbiter](https://actix.github.io/actix/actix/struct.Arbiter.html).
You can always get access to tokio handle via
[Arbiter::handle()](https://actix.github.io/actix/actix/struct.Arbiter.html#method.handle)
method.