diff --git a/Cargo.toml b/Cargo.toml index 7c55a6ffc..bb4b7b932 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,9 +85,11 @@ optional = true env_logger = "0.4" reqwest = "0.8" skeptic = "0.13" +serde_derive = "1.0" [build-dependencies] skeptic = "0.13" +serde_derive = "1.0" version_check = "0.1" [profile.release] diff --git a/guide/src/qs_3.md b/guide/src/qs_3.md index a34a46848..217744b40 100644 --- a/guide/src/qs_3.md +++ b/guide/src/qs_3.md @@ -71,14 +71,18 @@ fn main() { ## [WIP] Handler -A request handler can have different forms. +A request handler can by any object that implements +[`Handler` trait](../actix_web/struct.HttpResponse.html#implementations). -* Simple function that accepts `HttpRequest` and returns `HttpResponse` or any - type that can be converted into `HttpResponse`. -* Function that that accepts `HttpRequest` and returns `Stream`. -* Http actor, i.e. actor that has `HttpContext`as a context. +By default actix provdes several `Handler` implementations: -Actix provides response conversion for some standard types, like `&'static str`, `String`, etc. +* Simple function that accepts `HttpRequest` and returns any object that + can be converted to `HttpResponse` +* Function that accepts `HttpRequest` and returns `Result>` object. +* Function that accepts `HttpRequest` and return actor that has `HttpContext`as a context. + +Actix provides response conversion into `HttpResponse` for some standard types, +like `&'static str`, `String`, etc. For complete list of implementations check [HttpResponse documentation](../actix_web/struct.HttpResponse.html#implementations). @@ -101,3 +105,77 @@ fn index(req: HttpRequest) -> Bytes { Bytes::from_static("Hello world!") } ``` + +```rust,ignore +fn index(req: HttpRequest) -> Box> { + ... +} +``` + +### Custom conversion + +Let's create response for custom type that serializes to `application/json` response: + +```rust +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: String, +} + +/// we have to convert Error into HttpResponse as well, but with +/// specialization this could be handled genericly. +impl Into for MyObj { + fn into(self) -> HttpResponse { + let body = match serde_json::to_string(&self) { + Err(err) => return Error::from(err).into(), + Ok(body) => body, + }; + + // Create response and set content type + HttpResponse::Ok() + .content_type("application/json") + .body(body).unwrap() + } +} + +fn main() { + let sys = actix::System::new("example"); + + HttpServer::new( + Application::default("/") + .resource("/", |r| r.handler( + Method::GET, |req| {Ok(MyObj{name: "user".to_owned()})}))) + .serve::<_, ()>("127.0.0.1:8088").unwrap(); + + println!("Started http server: 127.0.0.1:8088"); + actix::Arbiter::system().send(actix::msgs::SystemExit(0)); // <- remove this line, this code stops system during testing + + let _ = sys.run(); +} +``` + +If `specialization` is enabled, conversion could be simplier: + +```rust,ignore +#[derive(Serialize)] +struct MyObj { + name: String, +} + +impl Into> for MyObj { + fn into(self) -> Result { + let body = serde_json::to_string(&self)?; + + Ok(HttpResponse::Ok() + .content_type("application/json") + .body(body)?) + } +} +``` diff --git a/src/route.rs b/src/route.rs index 17c952db0..63dff350d 100644 --- a/src/route.rs +++ b/src/route.rs @@ -67,6 +67,7 @@ impl Reply { } } +#[cfg(not(actix_nightly))] impl> From for Reply { fn from(item: T) -> Self { @@ -74,6 +75,24 @@ impl> From for Reply } } +#[cfg(actix_nightly)] +default impl> From for Reply +{ + fn from(item: T) -> Self { + Reply(ReplyItem::Message(item.into())) + } +} + +#[cfg(actix_nightly)] +default impl, E: Into> From> for Reply { + fn from(res: StdResult) -> Self { + match res { + Ok(val) => val.into().into(), + Err(err) => err.into().into(), + } + } +} + impl> From> for Reply { fn from(res: StdResult) -> Self { match res {