From f93463b3d98d30f47653acde12bf3e42ba278f68 Mon Sep 17 00:00:00 2001 From: messense Date: Fri, 12 Jul 2019 16:11:23 +0800 Subject: [PATCH] docs(examples): Update params example to use async await --- examples/params.rs | 127 +++++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 61 deletions(-) diff --git a/examples/params.rs b/examples/params.rs index 511e27bf..2589949a 100644 --- a/examples/params.rs +++ b/examples/params.rs @@ -1,96 +1,101 @@ -#![deny(warnings)] -extern crate futures; +#![feature(async_await)] +// #![deny(warnings)] // FIXME: https://github.com/rust-lang/rust/issues/62411 extern crate hyper; extern crate pretty_env_logger; extern crate url; -use futures::{future, Future, Stream}; - use hyper::{Body, Method, Request, Response, Server, StatusCode}; -use hyper::service::service_fn; +use hyper::service::{service_fn, make_service_fn}; use std::collections::HashMap; use url::form_urlencoded; +use futures_util::TryStreamExt; static INDEX: &[u8] = b"
Name:
Number:
"; static MISSING: &[u8] = b"Missing field"; static NOTNUMERIC: &[u8] = b"Number field is not numeric"; // Using service_fn, we can turn this function into a `Service`. -fn param_example(req: Request) -> Box, Error=hyper::Error> + Send> { +async fn param_example(req: Request) -> Result, hyper::Error> { match (req.method(), req.uri().path()) { (&Method::GET, "/") | (&Method::GET, "/post") => { - Box::new(future::ok(Response::new(INDEX.into()))) + Ok(Response::new(INDEX.into())) }, (&Method::POST, "/post") => { - Box::new(req.into_body().concat2().map(|b| { - // Parse the request body. form_urlencoded::parse - // always succeeds, but in general parsing may - // fail (for example, an invalid post of json), so - // returning early with BadRequest may be - // necessary. - // - // Warning: this is a simplified use case. In - // principle names can appear multiple times in a - // form, and the values should be rolled up into a - // HashMap>. However in this - // example the simpler approach is sufficient. - let params = form_urlencoded::parse(b.as_ref()).into_owned().collect::>(); + let b = req.into_body().try_concat().await?; + // Parse the request body. form_urlencoded::parse + // always succeeds, but in general parsing may + // fail (for example, an invalid post of json), so + // returning early with BadRequest may be + // necessary. + // + // Warning: this is a simplified use case. In + // principle names can appear multiple times in a + // form, and the values should be rolled up into a + // HashMap>. However in this + // example the simpler approach is sufficient. + let params = form_urlencoded::parse(b.as_ref()).into_owned().collect::>(); - // Validate the request parameters, returning - // early if an invalid input is detected. - let name = if let Some(n) = params.get("name") { - n + // Validate the request parameters, returning + // early if an invalid input is detected. + let name = if let Some(n) = params.get("name") { + n + } else { + return Ok(Response::builder() + .status(StatusCode::UNPROCESSABLE_ENTITY) + .body(MISSING.into()) + .unwrap()); + }; + let number = if let Some(n) = params.get("number") { + if let Ok(v) = n.parse::() { + v } else { - return Response::builder() + return Ok(Response::builder() .status(StatusCode::UNPROCESSABLE_ENTITY) - .body(MISSING.into()) - .unwrap(); - }; - let number = if let Some(n) = params.get("number") { - if let Ok(v) = n.parse::() { - v - } else { - return Response::builder() - .status(StatusCode::UNPROCESSABLE_ENTITY) - .body(NOTNUMERIC.into()) - .unwrap(); - } - } else { - return Response::builder() - .status(StatusCode::UNPROCESSABLE_ENTITY) - .body(MISSING.into()) - .unwrap(); - }; + .body(NOTNUMERIC.into()) + .unwrap()); + } + } else { + return Ok(Response::builder() + .status(StatusCode::UNPROCESSABLE_ENTITY) + .body(MISSING.into()) + .unwrap()); + }; - // Render the response. This will often involve - // calls to a database or web service, which will - // require creating a new stream for the response - // body. Since those may fail, other error - // responses such as InternalServiceError may be - // needed here, too. - let body = format!("Hello {}, your number is {}", name, number); - Response::new(body.into()) - })) + // Render the response. This will often involve + // calls to a database or web service, which will + // require creating a new stream for the response + // body. Since those may fail, other error + // responses such as InternalServiceError may be + // needed here, too. + let body = format!("Hello {}, your number is {}", name, number); + Ok(Response::new(body.into())) }, _ => { - Box::new(future::ok(Response::builder() - .status(StatusCode::NOT_FOUND) - .body(Body::empty()) - .unwrap())) + Ok(Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::empty()) + .unwrap()) } } - } -fn main() { +#[hyper::rt::main] +async fn main() -> Result<(), Box> { pretty_env_logger::init(); let addr = ([127, 0, 0, 1], 1337).into(); let server = Server::bind(&addr) - .serve(|| service_fn(param_example)) - .map_err(|e| eprintln!("server error: {}", e)); + .serve(make_service_fn(|_| { + async { + Ok::<_, hyper::Error>(service_fn(param_example)) + } + })); - hyper::rt::run(server); + println!("Listening on http://{}", addr); + + server.await?; + + Ok(()) }