docs(examples): update echo example to use async/await
This commit is contained in:
		
				
					committed by
					
						 Sean McArthur
						Sean McArthur
					
				
			
			
				
	
			
			
			
						parent
						
							22142943f4
						
					
				
				
					commit
					7ff8fccced
				
			| @@ -1,80 +1,80 @@ | |||||||
|  | #![feature(async_await)] | ||||||
| #![deny(warnings)] | #![deny(warnings)] | ||||||
| extern crate futures; |  | ||||||
| extern crate hyper; | extern crate hyper; | ||||||
|  |  | ||||||
| use futures::future; |  | ||||||
| use hyper::rt::{Future, Stream}; |  | ||||||
| use hyper::service::service_fn; |  | ||||||
| use hyper::{Body, Method, Request, Response, Server, StatusCode}; | use hyper::{Body, Method, Request, Response, Server, StatusCode}; | ||||||
|  | use hyper::service::{make_service_fn, service_fn}; | ||||||
| /// We need to return different futures depending on the route matched, | use futures_util::TryStreamExt; | ||||||
| /// and we can do that with an enum, such as `futures::Either`, or with |  | ||||||
| /// trait objects. |  | ||||||
| /// |  | ||||||
| /// A boxed Future (trait object) is used as it is easier to understand |  | ||||||
| /// and extend with more types. Advanced users could switch to `Either`. |  | ||||||
| type BoxFut = Box<dyn Future<Item = Response<Body>, Error = hyper::Error> + Send>; |  | ||||||
|  |  | ||||||
| /// This is our service handler. It receives a Request, routes on its | /// This is our service handler. It receives a Request, routes on its | ||||||
| /// path, and returns a Future of a Response. | /// path, and returns a Future of a Response. | ||||||
| fn echo(req: Request<Body>) -> BoxFut { | async fn echo(req: Request<Body>) -> Result<Response<Body>, hyper::Error> { | ||||||
|     let mut response = Response::new(Body::empty()); |  | ||||||
|  |  | ||||||
|     match (req.method(), req.uri().path()) { |     match (req.method(), req.uri().path()) { | ||||||
|         // Serve some instructions at / |         // Serve some instructions at / | ||||||
|         (&Method::GET, "/") => { |         (&Method::GET, "/") => { | ||||||
|             *response.body_mut() = Body::from("Try POSTing data to /echo"); |             Ok(Response::new(Body::from("Try POSTing data to /echo such as: `curl localhost:3000/echo -XPOST -d 'hello world'`"))) | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Simply echo the body back to the client. |         // Simply echo the body back to the client. | ||||||
|         (&Method::POST, "/echo") => { |         (&Method::POST, "/echo") => { | ||||||
|             *response.body_mut() = req.into_body(); |             Ok(Response::new(req.into_body())) | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Convert to uppercase before sending back to client. |         // Convert to uppercase before sending back to client using a stream. | ||||||
|         (&Method::POST, "/echo/uppercase") => { |         (&Method::POST, "/echo/uppercase") => { | ||||||
|             let mapping = req.into_body().map(|chunk| { |             let chunk_stream = req.into_body().map_ok(|chunk| { | ||||||
|                 chunk |                 chunk | ||||||
|                     .iter() |                     .iter() | ||||||
|                     .map(|byte| byte.to_ascii_uppercase()) |                     .map(|byte| byte.to_ascii_uppercase()) | ||||||
|                     .collect::<Vec<u8>>() |                     .collect::<Vec<u8>>() | ||||||
|             }); |             }); | ||||||
|  |             Ok(Response::new(Body::wrap_stream(chunk_stream))) | ||||||
|             *response.body_mut() = Body::wrap_stream(mapping); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Reverse the entire body before sending back to the client. |         // Reverse the entire body before sending back to the client. | ||||||
|         // |         // | ||||||
|         // Since we don't know the end yet, we can't simply stream |         // Since we don't know the end yet, we can't simply stream | ||||||
|         // the chunks as they arrive. So, this returns a different |         // the chunks as they arrive as we did with the above uppercase endpoint. | ||||||
|         // future, waiting on concatenating the full body, so that |         // So here we do `.await` on the future, waiting on concatenating the full body, | ||||||
|         // it can be reversed. Only then can we return a `Response`. |         // then afterwards the content can be reversed. Only then can we return a `Response`. | ||||||
|         (&Method::POST, "/echo/reversed") => { |         (&Method::POST, "/echo/reversed") => { | ||||||
|             let reversed = req.into_body().concat2().map(move |chunk| { |             let whole_chunk = req.into_body().try_concat().await; | ||||||
|                 let body = chunk.iter().rev().cloned().collect::<Vec<u8>>(); |  | ||||||
|                 *response.body_mut() = Body::from(body); |  | ||||||
|                 response |  | ||||||
|             }); |  | ||||||
|  |  | ||||||
|             return Box::new(reversed); |             let reversed_chunk = whole_chunk.map(move |chunk| { | ||||||
|  |                 chunk.iter().rev().cloned().collect::<Vec<u8>>() | ||||||
|  |  | ||||||
|  |             })?; | ||||||
|  |             Ok(Response::new(Body::from(reversed_chunk))) | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // The 404 Not Found route... |         // Return the 404 Not Found for other routes. | ||||||
|         _ => { |         _ => { | ||||||
|             *response.status_mut() = StatusCode::NOT_FOUND; |             let mut not_found = Response::default(); | ||||||
|  |             *not_found.status_mut() = StatusCode::NOT_FOUND; | ||||||
|  |             Ok(not_found) | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     Box::new(future::ok(response)) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| fn main() { |  | ||||||
|  | #[tokio::main] | ||||||
|  | async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { | ||||||
|     let addr = ([127, 0, 0, 1], 3000).into(); |     let addr = ([127, 0, 0, 1], 3000).into(); | ||||||
|  |  | ||||||
|  |     let service = make_service_fn(|_| { | ||||||
|  |         async { | ||||||
|  |             Ok::<_, hyper::Error>(service_fn(echo)) | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  |  | ||||||
|     let server = Server::bind(&addr) |     let server = Server::bind(&addr) | ||||||
|         .serve(|| service_fn(echo)) |         .serve(service); | ||||||
|         .map_err(|e| eprintln!("server error: {}", e)); |  | ||||||
|  |  | ||||||
|     println!("Listening on http://{}", addr); |     println!("Listening on http://{}", addr); | ||||||
|     hyper::rt::run(server); |  | ||||||
|  |     server.await?; | ||||||
|  |  | ||||||
|  |     Ok(()) | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user