From e35f8031b1ca55814cf0f9af6e96b39a403ca24f Mon Sep 17 00:00:00 2001 From: dowwie Date: Fri, 27 Apr 2018 15:30:29 -0400 Subject: [PATCH 1/2] ready to commit --- async_ex1/Cargo.toml | 15 +++++++ async_ex1/README.md | 18 ++++++++ async_ex1/src/main.rs | 101 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 async_ex1/Cargo.toml create mode 100644 async_ex1/README.md create mode 100644 async_ex1/src/main.rs diff --git a/async_ex1/Cargo.toml b/async_ex1/Cargo.toml new file mode 100644 index 00000000..cdfcde10 --- /dev/null +++ b/async_ex1/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "awc_examples" +version = "0.1.0" +authors = ["dowwie "] + +[dependencies] +actix = "0.5.6" +actix-web = { version = "^0.5", features=["alpn"] } +futures = "0.1" +serde = "1.0.43" +serde_derive = "1.0.43" +serde_json = "1.0.16" +validator = "0.6.3" +validator_derive = "0.6.5" +env_logger = "0.5.9" diff --git a/async_ex1/README.md b/async_ex1/README.md new file mode 100644 index 00000000..b6ce1614 --- /dev/null +++ b/async_ex1/README.md @@ -0,0 +1,18 @@ +This is a contrived example intended to illustrate a few important actix-web features. +*Imagine* that you have a process that involves 3 steps. The steps here +are dumb in that they do nothing other than call an +httpbin endpoint that returns the json that was posted to it. The intent here +is to illustrate how to chain these steps together as futures and return +a final result in a response. + +Actix-web features illustrated here include: + 1. handling json input param + 2. validating user-submitted parameters using the 'validator' crate + 2. actix-web client features: + - POSTing json body + 3. chaining futures into a single response used by an asynch endpoint + + +Example query from the command line using httpie: + ```http post 127.0.0.1:8088/something id=1 name=JohnDoe``` + diff --git a/async_ex1/src/main.rs b/async_ex1/src/main.rs new file mode 100644 index 00000000..7b76dd97 --- /dev/null +++ b/async_ex1/src/main.rs @@ -0,0 +1,101 @@ +// This is a contrived example intended to illustrate actix-web features. +// *Imagine* that you have a process that involves 3 steps. The steps here +// are dumb in that they do nothing other than call an +// httpbin endpoint that returns the json that was posted to it. The intent here +// is to illustrate how to chain these steps together as futures and return +// a final result in a response. +// +// Actix-web features illustrated here include: +// 1. handling json input param +// 2. validating user-submitted parameters using the 'validator' crate +// 2. actix-web client features: +// - POSTing json body +// 3. chaining futures into a single response used by an asynch endpoint + +extern crate actix; +extern crate actix_web; +extern crate serde; +#[macro_use] +extern crate serde_derive; +extern crate serde_json; +#[macro_use] +extern crate validator_derive; +extern crate futures; +extern crate validator; +extern crate env_logger; + +use std::time::Duration; +use futures::{future::ok as fut_ok, Future}; +use std::collections::HashMap; +use actix_web::{client, dev::Handler, http::Method, server, App, AsyncResponder, Body, Error, + HttpMessage, HttpRequest, HttpResponse, Json, Result}; +use validator::{Validate, ValidationError}; + +#[derive(Debug, Validate, Deserialize, Serialize)] +struct SomeData { + #[validate(length(min = "1", max = "1000000"))] + id: String, + #[validate(length(min = "1", max = "100"))] + name: String, +} + +#[derive(Debug, Deserialize)] +struct HttpBinResponse { + args: HashMap, + data: String, + files: HashMap, + form: HashMap, + headers: HashMap, + json: SomeData, + origin: String, + url: String +} + +/// post json to httpbin, get it back in the response body, return deserialized +fn step_x(data: SomeData) -> Box> { + Box::new( + client::ClientRequest::post("https://httpbin.org/post") + .json(data).unwrap() + .send() + .conn_timeout(Duration::from_secs(10)) + .map_err(Error::from) // <- convert SendRequestError to an Error + .and_then( + |resp| resp.body() // <- this is MessageBody type, resolves to complete body + .from_err() // <- convert PayloadError to a Error + .and_then(|body| { + let resp: HttpBinResponse = serde_json::from_slice(&body).unwrap(); + fut_ok(resp.json) + }) + ), + ) +} + +fn create_something(some_data: Json) -> Box> { + step_x(some_data.into_inner()) + .and_then(|some_data_2| { + step_x(some_data_2).and_then(|some_data_3| { + step_x(some_data_3).and_then(|d| + Ok(HttpResponse::Ok() + .content_type("application/json") + .body(serde_json::to_string(&d).unwrap()) + .into())) + }) + }) + .responder() +} + +fn main() { + env_logger::init(); + let sys = actix::System::new("asyncio_example"); + + server::new(move || { + App::new().resource("/something", |r| { + r.method(Method::POST).with(create_something) + }) + }).bind("127.0.0.1:8088") + .unwrap() + .start(); + + println!("Started http server: 127.0.0.1:8088"); + let _ = sys.run(); +} From a313accc55c3651f0413b90cbf31252c82ab720f Mon Sep 17 00:00:00 2001 From: dowwie Date: Fri, 27 Apr 2018 15:31:34 -0400 Subject: [PATCH 2/2] updated README formatting --- async_ex1/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/async_ex1/README.md b/async_ex1/README.md index b6ce1614..11bbbeed 100644 --- a/async_ex1/README.md +++ b/async_ex1/README.md @@ -1,4 +1,5 @@ This is a contrived example intended to illustrate a few important actix-web features. + *Imagine* that you have a process that involves 3 steps. The steps here are dumb in that they do nothing other than call an httpbin endpoint that returns the json that was posted to it. The intent here @@ -6,6 +7,7 @@ is to illustrate how to chain these steps together as futures and return a final result in a response. Actix-web features illustrated here include: + 1. handling json input param 2. validating user-submitted parameters using the 'validator' crate 2. actix-web client features: