Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some helper functions for common usage #53

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "*"
Expand Down
24 changes: 24 additions & 0 deletions examples/helpers.rs
Original file line number Diff line number Diff line change
@@ -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<Response> {
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();
}
77 changes: 77 additions & 0 deletions src/helpers.rs
Original file line number Diff line number Diff line change
@@ -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<Response> {
/// let params = try!(require_body_params(req));
/// ```
pub fn require_body_params(req: &mut Request) -> IronResult<QueryMap> {
req.get::<UrlEncodedBody>()
.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<Response> {
/// let params = try!(require_query_params(req));
///
/// ```
pub fn require_query_params(req: &mut Request) -> IronResult<QueryMap> {
req.get::<UrlEncodedQuery>()
.map_err(|err| IronError::new(err, status::BadRequest))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we might be able to avoid these extra functions if we impl Into<IronError> for our own error types?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally speaking I think it's wrong to do so - you want to specify an intelligent and semantic response when there is an error, not just toss 400 at everything.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of those helpers is IMO that I don't care about that.

}

/// Returns the first parameter for a given parameter name, or a `MissingParamError`
///
/// # Examples
/// ```
/// fn request_handler(req: &mut Request) => IronResult<Response> {
/// let params = try!(require_body_params(req));
/// let search = try!(require_parameter(&params, "search"));
///
/// ```
pub fn require_parameter<'a, T: Into<String>>(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");
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<UrlEncodedQuery>()`
Expand Down