From a578262f735a470c85f27f49c604a4f03a94ed9e Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Mon, 25 Dec 2017 08:12:13 -0800 Subject: [PATCH] update json example and guide info --- examples/json/src/main.rs | 41 +++++++++++++++++++++++++++++++++++++-- guide/src/qs_5.md | 6 +++--- guide/src/qs_7.md | 19 ++++++++++++++---- 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/examples/json/src/main.rs b/examples/json/src/main.rs index fae29053d..9bc8bebcd 100644 --- a/examples/json/src/main.rs +++ b/examples/json/src/main.rs @@ -1,12 +1,14 @@ extern crate actix; extern crate actix_web; +extern crate bytes; extern crate futures; extern crate env_logger; extern crate serde_json; #[macro_use] extern crate serde_derive; use actix_web::*; -use futures::Future; +use bytes::BytesMut; +use futures::{Future, Stream}; #[derive(Debug, Serialize, Deserialize)] struct MyObj { @@ -14,8 +16,10 @@ struct MyObj { number: i32, } +/// This handler uses `HttpRequest::json()` for loading json object. fn index(mut req: HttpRequest) -> Box> { - req.json().from_err() + req.json() + .from_err() // convert all errors into `Error` .and_then(|val: MyObj| { println!("model: {:?}", val); Ok(httpcodes::HTTPOk.build().json(val)?) // <- send response @@ -23,6 +27,38 @@ fn index(mut req: HttpRequest) -> Box> { .responder() } + +const MAX_SIZE: usize = 262_144; // max payload size is 256k + +/// This handler manually load request payload and parse json +fn index_manual(mut req: HttpRequest) -> Box> { + // readany() returns asynchronous stream of Bytes objects + req.payload_mut().readany() + // `Future::from_err` acts like `?` in that it coerces the error type from + // the future into the final error type + .from_err() + + // `fold` will asynchronously read each chunk of the request body and + // call supplied closure, then it resolves to result of closure + .fold(BytesMut::new(), move |mut body, chunk| { + // limit max size of in-memory payload + if (body.len() + chunk.len()) > MAX_SIZE { + Err(error::ErrorBadRequest("overflow")) + } else { + body.extend_from_slice(&chunk); + Ok(body) + } + }) + // `Future::and_then` can be used to merge an asynchronous workflow with a + // synchronous workflow + .and_then(|body| { + // body is loaded, now we can deserialize json + let obj = serde_json::from_slice::(&body)?; + Ok(httpcodes::HTTPOk.build().json(obj)?) // <- send response + }) + .responder() +} + fn main() { ::std::env::set_var("RUST_LOG", "actix_web=info"); let _ = env_logger::init(); @@ -32,6 +68,7 @@ fn main() { Application::new() // enable logger .middleware(middlewares::Logger::default()) + .resource("/manual", |r| r.method(Method::POST).f(index_manual)) .resource("/", |r| r.method(Method::POST).f(index))}) .bind("127.0.0.1:8080").unwrap() .start(); diff --git a/guide/src/qs_5.md b/guide/src/qs_5.md index 65ee24c3f..5f8042179 100644 --- a/guide/src/qs_5.md +++ b/guide/src/qs_5.md @@ -13,9 +13,9 @@ a response object. More informatin is available in [handler section](../qs_4.htm Resource configuraiton is the act of adding a new resource to an application. A resource has a name, which acts as an identifier to be used for URL generation. The name also allows developers to add routes to existing resources. -A resource also has a pattern, meant to match against the *PATH* portion of a *URL* -(the portion following the scheme and port, e.g., */foo/bar* in the -*URL* *http://localhost:8080/foo/bar*). +A resource also has a pattern, meant to match against the *PATH* portion of a *URL*, +it does not match against *QUERY* portion (the portion following the scheme and +port, e.g., */foo/bar* in the *URL* *http://localhost:8080/foo/bar?q=value*). The [Application::resource](../actix_web/struct.Application.html#method.resource) methods add a single resource to application routing table. This method accepts *path pattern* diff --git a/guide/src/qs_7.md b/guide/src/qs_7.md index 8385bdbd4..a51c5c8a6 100644 --- a/guide/src/qs_7.md +++ b/guide/src/qs_7.md @@ -69,7 +69,6 @@ deserialized value. # extern crate actix; # extern crate actix_web; # extern crate futures; -# extern crate env_logger; # extern crate serde_json; # #[macro_use] extern crate serde_derive; # use actix_web::*; @@ -95,8 +94,18 @@ Or you can manually load payload into memory and ther deserialize it. Here is simple example. We will deserialize *MyObj* struct. We need to load request body first and then deserialize json into object. -```rust,ignore -fn index(mut req: HttpRequest) -> Future { +```rust +# extern crate actix_web; +# extern crate futures; +# use actix_web::*; +# #[macro_use] extern crate serde_derive; +extern crate serde_json; +use futures::{Future, Stream}; + +#[derive(Serialize, Deserialize)] +struct MyObj {name: String, number: i32} + +fn index(mut req: HttpRequest) -> Box> { // `concat2` will asynchronously read each chunk of the request body and // return a single, concatenated, chunk req.payload_mut().readany().concat2() @@ -109,10 +118,12 @@ fn index(mut req: HttpRequest) -> Future { let obj = serde_json::from_slice::(&body)?; Ok(httpcodes::HTTPOk.build().json(obj)?) // <- send response }) + .responder() } +# fn main() {} ``` -Example is available in +Complete example for both options is available in [examples directory](https://github.com/actix/actix-web/tree/master/examples/json/).