Merge pull request #1400 from jolhoeft/params_example
docs(server): Add a forms server example
This commit is contained in:
		| @@ -41,6 +41,7 @@ unicase = "2.0" | |||||||
| num_cpus = "1.0" | num_cpus = "1.0" | ||||||
| pretty_env_logger = "0.1" | pretty_env_logger = "0.1" | ||||||
| spmc = "0.2" | spmc = "0.2" | ||||||
|  | url = "1.0" | ||||||
|  |  | ||||||
| [features] | [features] | ||||||
| default = ["server-proto"] | default = ["server-proto"] | ||||||
|   | |||||||
							
								
								
									
										106
									
								
								examples/params.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								examples/params.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | |||||||
|  | #![deny(warnings)] | ||||||
|  | extern crate futures; | ||||||
|  | extern crate hyper; | ||||||
|  | extern crate pretty_env_logger; | ||||||
|  | extern crate url; | ||||||
|  |  | ||||||
|  | use futures::{Future, Stream}; | ||||||
|  |  | ||||||
|  | use hyper::{Get, Post, StatusCode}; | ||||||
|  | use hyper::header::ContentLength; | ||||||
|  | use hyper::server::{Http, Service, Request, Response}; | ||||||
|  |  | ||||||
|  | use std::collections::HashMap; | ||||||
|  | use url::form_urlencoded; | ||||||
|  |  | ||||||
|  | static INDEX: &[u8] = b"<html><body><form action=\"post\" method=\"post\">Name: <input type=\"text\" name=\"name\"><br>Number: <input type=\"text\" name=\"number\"><br><input type=\"submit\"></body></html>"; | ||||||
|  | static MISSING: &[u8] = b"Missing field"; | ||||||
|  | static NOTNUMERIC: &[u8] = b"Number field is not numeric"; | ||||||
|  |  | ||||||
|  | struct ParamExample; | ||||||
|  |  | ||||||
|  | impl Service for ParamExample { | ||||||
|  |     type Request = Request; | ||||||
|  |     type Response = Response; | ||||||
|  |     type Error = hyper::Error; | ||||||
|  |     type Future = Box<Future<Item = Self::Response, Error = Self::Error>>; | ||||||
|  |  | ||||||
|  |     fn call(&self, req: Request) -> Self::Future { | ||||||
|  |         match (req.method(), req.path()) { | ||||||
|  |             (&Get, "/") | (&Get, "/post") => { | ||||||
|  |                 Box::new(futures::future::ok(Response::new() | ||||||
|  |                                              .with_header(ContentLength(INDEX.len() as u64)) | ||||||
|  |                                              .with_body(INDEX))) | ||||||
|  |             }, | ||||||
|  |             (&Post, "/post") => { | ||||||
|  |                 Box::new(req.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<String, Vec<String>>. However in this | ||||||
|  |                     // example the simpler approach is sufficient. | ||||||
|  |                     let params = form_urlencoded::parse(b.as_ref()).into_owned().collect::<HashMap<String, String>>(); | ||||||
|  |  | ||||||
|  |                     // Validate the request parameters, returning | ||||||
|  |                     // early if an invalid input is detected. | ||||||
|  |                     let name = if let Some(n) = params.get("name") { | ||||||
|  |                         n | ||||||
|  |                     } else { | ||||||
|  |                         return Response::new() | ||||||
|  |                             .with_status(StatusCode::UnprocessableEntity) | ||||||
|  |                             .with_header(ContentLength(MISSING.len() as u64)) | ||||||
|  |                             .with_body(MISSING); | ||||||
|  |                     }; | ||||||
|  |                     let number = if let Some(n) = params.get("number") { | ||||||
|  |                         if let Ok(v) = n.parse::<f64>() { | ||||||
|  |                             v | ||||||
|  |                         } else { | ||||||
|  |                             return Response::new() | ||||||
|  |                                 .with_status(StatusCode::UnprocessableEntity) | ||||||
|  |                                 .with_header(ContentLength(NOTNUMERIC.len() as u64)) | ||||||
|  |                                 .with_body(NOTNUMERIC); | ||||||
|  |                         } | ||||||
|  |                     } else { | ||||||
|  |                         return Response::new() | ||||||
|  |                             .with_status(StatusCode::UnprocessableEntity) | ||||||
|  |                             .with_header(ContentLength(MISSING.len() as u64)) | ||||||
|  |                             .with_body(MISSING); | ||||||
|  |                     }; | ||||||
|  |  | ||||||
|  |                     // 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() | ||||||
|  |                         .with_header(ContentLength(body.len() as u64)) | ||||||
|  |                         .with_body(body) | ||||||
|  |                 })) | ||||||
|  |             }, | ||||||
|  |             _ => { | ||||||
|  |                 Box::new(futures::future::ok(Response::new() | ||||||
|  |                                     .with_status(StatusCode::NotFound))) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | fn main() { | ||||||
|  |     pretty_env_logger::init().unwrap(); | ||||||
|  |     let addr = "127.0.0.1:1337".parse().unwrap(); | ||||||
|  |  | ||||||
|  |     let mut server = Http::new().bind(&addr, || Ok(ParamExample)).unwrap(); | ||||||
|  |     server.no_proto(); | ||||||
|  |     println!("Listening on http://{} with 1 thread.", server.local_addr().unwrap()); | ||||||
|  |     server.run().unwrap(); | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user