diff --git a/guide/src/qs_3.md b/guide/src/qs_3.md index 0e06371a..60b16f53 100644 --- a/guide/src/qs_3.md +++ b/guide/src/qs_3.md @@ -56,7 +56,7 @@ fn index(req: HttpRequest) -> String { fn main() { Application::build("/", AppState{counter: Cell::new(0)}) - .resource("/", |r| r.handler(Method::GET, index))) + .resource("/", |r| r.handler(Method::GET, index)) .finish(); } ``` @@ -143,7 +143,7 @@ fn main() { HttpServer::new( Application::default("/") .resource("/", |r| r.handler( - Method::GET, |req| {Ok(MyObj{name: "user".to_owned()})}))) + Method::GET, |req| {MyObj{name: "user".to_owned()}}))) .serve::<_, ()>("127.0.0.1:8088").unwrap(); println!("Started http server: 127.0.0.1:8088"); @@ -166,3 +166,35 @@ impl Into> for MyObj { } } ``` + +### Async handlers + +There are two different types of async handlers. + +Response object could be generated asynchronously. In this case handle must +return `Future` object that resolves to `HttpResponse`, i.e: + +```rust,ignore +fn index(req: HttpRequest) -> Box> { + ... +} +``` + +This handler can be registered with `ApplicationBuilder::async()` and +`Resource::async()` methods. + +Or response body can be generated asynchronously. In this case body +must implement stream trait `Stream`, i.e: + + +```rust,ignore +fn index(req: HttpRequest) -> HttpResponse { + let body: Box> = Box::new(SomeStream::new()); + + HttpResponse::Ok(). + .content_type("application/json") + .body(Body::Streaming(body)).unwrap() +} +``` + +Both methods could be combined. (i.e Async response with streaming body) diff --git a/src/application.rs b/src/application.rs index 1530e551..4fe5f1dd 100644 --- a/src/application.rs +++ b/src/application.rs @@ -1,10 +1,13 @@ use std::rc::Rc; use std::collections::HashMap; +use futures::Future; -use route::{RouteHandler, WrapHandler, Reply, Handler}; +use error::Error; +use route::{RouteHandler, Reply, Handler, WrapHandler, AsyncHandler}; use resource::Resource; use recognizer::{RouteRecognizer, check_pattern}; use httprequest::HttpRequest; +use httpresponse::HttpResponse; use channel::HttpHandler; use pipeline::Pipeline; use middlewares::Middleware; @@ -204,6 +207,18 @@ impl ApplicationBuilder where S: 'static { self } + /// This method register async handler for specified path prefix. + /// Any path that starts with this prefix matches handler. + pub fn async(&mut self, path: P, handler: F) -> &mut Self + where F: Fn(HttpRequest) -> R + 'static, + R: Future + 'static, + P: Into, + { + self.parts.as_mut().expect("Use after finish") + .handlers.insert(path.into(), Box::new(AsyncHandler::new(handler))); + self + } + /// Construct application pub fn middleware(&mut self, mw: T) -> &mut Self where T: Middleware + 'static diff --git a/src/resource.rs b/src/resource.rs index a21b5e34..6e82b60a 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -5,7 +5,7 @@ use http::Method; use futures::Future; use error::Error; -use route::{Reply, RouteHandler, WrapHandler, Handler, StreamHandler}; +use route::{Reply, Handler, RouteHandler, AsyncHandler, WrapHandler}; use httprequest::HttpRequest; use httpresponse::HttpResponse; use httpcodes::{HTTPNotFound, HTTPMethodNotAllowed}; @@ -70,7 +70,7 @@ impl Resource where S: 'static { where F: Fn(HttpRequest) -> R + 'static, R: Future + 'static, { - self.routes.insert(method, Box::new(StreamHandler::new(handler))); + self.routes.insert(method, Box::new(AsyncHandler::new(handler))); } /// Default handler is used if no matched route found. diff --git a/src/route.rs b/src/route.rs index 63dff350..1550751c 100644 --- a/src/route.rs +++ b/src/route.rs @@ -154,7 +154,7 @@ impl RouteHandler for WrapHandler /// Async route handler pub(crate) -struct StreamHandler +struct AsyncHandler where F: Fn(HttpRequest) -> R + 'static, R: Future + 'static, S: 'static, @@ -163,17 +163,17 @@ struct StreamHandler s: PhantomData, } -impl StreamHandler +impl AsyncHandler where F: Fn(HttpRequest) -> R + 'static, R: Future + 'static, S: 'static, { pub fn new(f: F) -> Self { - StreamHandler{f: Box::new(f), s: PhantomData} + AsyncHandler{f: Box::new(f), s: PhantomData} } } -impl RouteHandler for StreamHandler +impl RouteHandler for AsyncHandler where F: Fn(HttpRequest) -> R + 'static, R: Future + 'static, S: 'static,