From cbb81bc747da20ab98f0338d9ac878391c9089d3 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 20 Dec 2017 15:12:43 -0800 Subject: [PATCH] json request example --- examples/json/Cargo.toml | 16 ++++++++++ examples/json/client.py | 17 +++++++++++ examples/json/src/main.rs | 64 +++++++++++++++++++++++++++++++++++++++ guide/src/qs_7.md | 41 ++++++++++++++++++++++++- 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 examples/json/Cargo.toml create mode 100644 examples/json/client.py create mode 100644 examples/json/src/main.rs diff --git a/examples/json/Cargo.toml b/examples/json/Cargo.toml new file mode 100644 index 000000000..468b04900 --- /dev/null +++ b/examples/json/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "json-example" +version = "0.1.0" +authors = ["Nikolay Kim "] + +[dependencies] +bytes = "0.4" +futures = "0.1" +env_logger = "*" + +serde = "1.0" +serde_json = "1.0" +serde_derive = "1.0" + +actix = "^0.3.1" +actix-web = { git = "https://github.com/actix/actix-web.git" } diff --git a/examples/json/client.py b/examples/json/client.py new file mode 100644 index 000000000..31429443d --- /dev/null +++ b/examples/json/client.py @@ -0,0 +1,17 @@ +# This script could be used for actix-web multipart example test +# just start server and run client.py + +import json +import asyncio +import aiohttp + +async def req(): + resp = await aiohttp.ClientSession().request( + "post", 'http://localhost:8080/', + data=json.dumps({"name": "Test user", "number": 100}), + headers={"content-type": "application/json"}) + print(str(resp)) + assert 200 == resp.status + + +asyncio.get_event_loop().run_until_complete(req()) diff --git a/examples/json/src/main.rs b/examples/json/src/main.rs new file mode 100644 index 000000000..c271c12b0 --- /dev/null +++ b/examples/json/src/main.rs @@ -0,0 +1,64 @@ +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 bytes::BytesMut; +use futures::Stream; +use futures::future::{Future, ok, err, result}; + +#[derive(Debug, Deserialize)] +struct MyObj { + name: String, + number: i32, +} + +fn index(mut req: HttpRequest) -> Result>> { + // check content-type, early error exit + if req.content_type() != "application/json" { + return Err(error::ErrorBadRequest("wrong content-type").into()) + } + + Ok(Box::new( + // load request body + req.payload_mut() + .readany() + .fold(BytesMut::new(), |mut body, chunk| { + body.extend(chunk); + result::<_, error::PayloadError>(Ok(body)) + }) + .map_err(|e| Error::from(e)) + .and_then(|body| { + // body is loaded, now we can deserialize json + match serde_json::from_slice::(&body) { + Ok(obj) => { + println!("MODEL: {:?}", obj); // <- do something with payload + ok(httpcodes::HTTPOk.response()) // <- send response + }, + Err(e) => { + err(error::ErrorBadRequest(e).into()) + } + } + }))) +} + +fn main() { + ::std::env::set_var("RUST_LOG", "actix_web=info"); + let _ = env_logger::init(); + let sys = actix::System::new("json-example"); + + HttpServer::new(|| { + Application::new() + // enable logger + .middleware(middlewares::Logger::default()) + .resource("/", |r| r.method(Method::POST).f(index))}) + .bind("127.0.0.1:8080").unwrap() + .start(); + + println!("Started http server: 127.0.0.1:8080"); + let _ = sys.run(); +} diff --git a/guide/src/qs_7.md b/guide/src/qs_7.md index b69e67899..bb1a14367 100644 --- a/guide/src/qs_7.md +++ b/guide/src/qs_7.md @@ -55,7 +55,46 @@ fn index(req: HttpRequest) -> HttpResponse { } # fn main() {} ``` - + + +## JSON Request + +Unfortunately, because of async nature of actix web framework, deserializing json +requests is not very ergonomic process. First you need to load whole body into +temporal storage and only then you can deserialize it. + +Here is simple example. We will deserialize *MyObj* struct. + +```rust,ignore +#[derive(Debug, Deserialize)] +struct MyObj { + name: String, + number: i32, +} +``` + +We need to load request body first. + +```rust,ignore +fn index(mut req: HttpRequest) -> Future { + + req.payload_mut().readany() + .fold(BytesMut::new(), |mut body, chunk| { // <- load request body + body.extend(chunk); + result::<_, error::PayloadError>(Ok(body)) + }) + .and_then(|body| { // <- body is loaded, now we can deserialize json + let obj = serde_json::from_slice::(&body).unwrap(); + println!("MODEL: {:?}", obj); // <- do something with payload + ok(httpcodes::HTTPOk.response()) // <- send response + }) +} +``` + +Full example is available in +[examples directory](https://github.com/actix/actix-web/tree/master/examples/json/). + + ## JSON Response The `Json` type allows you to respond with well-formed JSON data: simply return a value of