1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-25 00:12:59 +01:00
actix-extras/guide/src/qs_4.md
2017-12-20 23:27:30 -08:00

4.0 KiB

Handler

A request handler can by any object that implements Handler trait. Request handling happen in two stages. First handler object get called. Handle can return any object that implements Responder trait. Then respond_to() get called on returned object. And finally result of the respond_to() call get converted to Reply object.

By default actix provides Responder implementations for some standard types, like &'static str, String, etc. For complete list of implementations check Responder documentation.

Examples of valid handlers:

fn index(req: HttpRequest) -> &'static str {
    "Hello world!"
}
fn index(req: HttpRequest) -> String {
    "Hello world!".to_owned()
}
fn index(req: HttpRequest) -> Bytes {
    Bytes::from_static("Hello world!")
}
fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
    ...
}

Response with custom type

To return custom type directly from handler function type needs to implement Responder trait. Let's create response for custom type that serializes to application/json response:

# extern crate actix;
# extern crate actix_web;
extern crate serde;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
use actix_web::*;

#[derive(Serialize)]
struct MyObj {
    name: &'static str,
}

/// Responder
impl Responder for MyObj {
    type Item = HttpResponse;
    type Error = Error;

    fn respond_to(self, req: HttpRequest) -> Result<HttpResponse> {
        let body = serde_json::to_string(&self)?;

        // Create response and set content type
        Ok(HttpResponse::Ok()
            .content_type("application/json")
            .body(body)?)
    }
}

/// Because `MyObj` implements `Responder`, it is possible to return it directly
fn index(req: HttpRequest) -> MyObj {
    MyObj{name: "user"}
}

fn main() {
    let sys = actix::System::new("example");

    HttpServer::new(
        || Application::new()
            .resource("/", |r| r.method(Method::GET).f(index)))
        .bind("127.0.0.1:8088").unwrap()
        .start();

    println!("Started http server: 127.0.0.1:8088");
#    actix::Arbiter::system().send(actix::msgs::SystemExit(0));
    let _ = sys.run();
}

Async handlers

There are two different types of async handlers.

Response object could be generated asynchronously or more precisely, any type that implements Responder trait. In this case handle must return Future object that resolves to Responder type, i.e:

# 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()))
}

fn index2(req: HttpRequest) -> FutureResult<&'static str, Error> {
    result(Ok("Welcome!"))
}

fn main() {
    Application::new()
        .resource("/async", |r| r.route().a(index))
        .resource("/", |r| r.route().a(index2))
        .finish();
}

Or response body can be generated asynchronously. In this case body must implement stream trait Stream<Item=Bytes, Error=Error>, i.e:

# extern crate actix_web;
# extern crate futures;
# extern crate bytes;
# use actix_web::*;
# use bytes::Bytes;
# use futures::stream::once;
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))).unwrap()
}

fn main() {
    Application::new()
        .resource("/async", |r| r.f(index))
        .finish();
}

Both methods could be combined. (i.e Async response with streaming body)