diff --git a/Cargo.toml b/Cargo.toml index d63743e..fdbb453 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,10 @@ documentation = "http://ironframework.io/doc/urlencoded/" description = "Decoding middleware for url-encoded data. For use with Iron." license = "MIT" +[lib] +name = "urlencoded" +doctest = false + [dependencies] iron = "*" url = "*" diff --git a/examples/helpers.rs b/examples/helpers.rs new file mode 100644 index 0000000..e3eb022 --- /dev/null +++ b/examples/helpers.rs @@ -0,0 +1,24 @@ +//! This example uses helper functions instead of direct interface. +//! +//! It cannot differentiate between a single and repeated parameter and will +//! fail with 400 as soon as either the body or the required parameter are not +//! provided. + +extern crate iron; +extern crate urlencoded; + +use iron::prelude::*; +use iron::status; +use urlencoded::helpers::{require_body_params, require_parameter}; + +fn log_post_data(req: &mut Request) -> IronResult { + let hashmap = try!(require_body_params(req)); + let name = try!(require_parameter(&hashmap, "name")); + + Ok(Response::with((status::Ok, format!("Hello {}", name)))) +} + +// Test with `curl -i -X POST "http://localhost:3000/" --data "name=world"` +fn main() { + Iron::new(log_post_data).http("127.0.0.1:3000").unwrap(); +} diff --git a/src/helpers.rs b/src/helpers.rs new file mode 100644 index 0000000..f844b3e --- /dev/null +++ b/src/helpers.rs @@ -0,0 +1,77 @@ +//! Helpers for the urlencoded module +//! +//! Provides one liners for the common usage of urlencoded + +use ::iron::prelude::*; +use ::iron::status; +use ::std::fmt::{Display,Formatter}; +use ::std::fmt::Error as FmtError; +use ::std::error::Error as StdError; +use super::{UrlEncodedBody,UrlEncodedQuery,QueryMap}; + +/// Error returned when the requested parameter is missing +#[derive(Debug, PartialEq)] +pub struct MissingParamError { + name: String +} + +impl StdError for MissingParamError { + fn description(&self) -> &str { + "Missing parameter" + } +} + +impl Display for MissingParamError { + fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { + write!(f, "Missing parameter {}", self.name) + } +} + +/// Returns the parameters hashmap constructed from the request body +/// +/// # Examples +/// ``` +/// fn request_handler(req: &mut Request) => IronResult { +/// let params = try!(require_body_params(req)); +/// ``` +pub fn require_body_params(req: &mut Request) -> IronResult { + req.get::() + .map_err(|err| IronError::new(err, status::BadRequest)) +} + +/// Returns the parameters hashmap constructed from the request query +/// +/// # Examples +/// ``` +/// fn request_handler(req: &mut Request) => IronResult { +/// let params = try!(require_query_params(req)); +/// +/// ``` +pub fn require_query_params(req: &mut Request) -> IronResult { + req.get::() + .map_err(|err| IronError::new(err, status::BadRequest)) +} + +/// Returns the first parameter for a given parameter name, or a `MissingParamError` +/// +/// # Examples +/// ``` +/// fn request_handler(req: &mut Request) => IronResult { +/// let params = try!(require_body_params(req)); +/// let search = try!(require_parameter(¶ms, "search")); +/// +/// ``` +pub fn require_parameter<'a, T: Into>(hashmap: &'a QueryMap, name: T) -> IronResult<&'a String> { + let name_val = name.into(); + hashmap.get(&name_val) + .and_then(|vals| vals.first()) + .ok_or(IronError::new(MissingParamError { name: name_val }, status::BadRequest)) +} + +#[test] +fn test_require_single() { + let mut hash = QueryMap::new(); + hash.insert("var".to_string(), vec!["value".to_string()]); + let val = require_parameter(&hash, "var").unwrap(); + assert_eq!(val, "value"); +} diff --git a/src/lib.rs b/src/lib.rs index 70153b1..279dfa1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,8 @@ use std::collections::hash_map::Entry::*; use std::fmt; use std::error::Error as StdError; +pub mod helpers; + /// Plugin for `Request` that extracts URL encoded data from the URL query string. /// /// Use it like this: `req.get_ref::()`