diff --git a/src/api3.rs b/src/api3.rs index 96fb5bf4..9dbb5938 100644 --- a/src/api3.rs +++ b/src/api3.rs @@ -34,7 +34,7 @@ pub fn router() -> MethodInfo { description: "This is a simple test.", parameters: parameter!{ force => Boolean!{ - optional => Some(true), + optional => true, description => "Test for boolean options." } }, diff --git a/src/json_schema.rs b/src/json_schema.rs index 69d59dfa..2af76b38 100644 --- a/src/json_schema.rs +++ b/src/json_schema.rs @@ -7,23 +7,23 @@ pub type PropertyMap = HashMap<&'static str, Jss>; #[derive(Debug)] pub struct JssBoolean { pub description: &'static str, - pub optional: Option, + pub optional: bool, pub default: Option, } #[derive(Debug)] pub struct JssInteger { pub description: &'static str, - pub optional: Option, - pub minimum: Option, - pub maximum: Option, - pub default: Option, + pub optional: bool, + pub minimum: Option, + pub maximum: Option, + pub default: Option, } #[derive(Debug)] pub struct JssString { pub description: &'static str, - pub optional: Option, + pub optional: bool, pub default: Option<&'static str>, pub min_length: Option, pub max_length: Option, @@ -32,15 +32,15 @@ pub struct JssString { #[derive(Debug)] pub struct JssArray { pub description: &'static str, - pub optional: Option, + pub optional: bool, pub items: Box, } #[derive(Debug)] pub struct JssObject { pub description: &'static str, - pub optional: Option, - pub additional_properties: Option, + pub optional: bool, + pub additional_properties: bool, pub properties: HashMap<&'static str, Jss>, } @@ -56,7 +56,7 @@ pub enum Jss { pub const DEFAULTBOOL: JssBoolean = JssBoolean { description: "", - optional: None, + optional: false, default: None, }; @@ -69,7 +69,7 @@ macro_rules! Boolean { pub const DEFAULTINTEGER: JssInteger = JssInteger { description: "", - optional: None, + optional: false, default: None, minimum: None, maximum: None, @@ -84,7 +84,7 @@ macro_rules! Integer { pub const DEFAULTSTRING: JssString = JssString { description: "", - optional: None, + optional: false, default: None, min_length: None, max_length: None, @@ -102,8 +102,8 @@ macro_rules! parameter { ($($name:ident => $e:expr),*) => {{ let inner = JssObject { description: "", - optional: None, - additional_properties: None, + optional: false, + additional_properties: false, properties: { let mut map = HashMap::<&'static str, Jss>::new(); $( @@ -117,12 +117,106 @@ macro_rules! parameter { }} } +fn parse_simple_value(value_str: &str, schema: &Jss) -> Result { -pub fn parse_parameter_strings(data: &Vec<(String, String)>, schema: &Jss) -> Result { + let value = match schema { + Jss::Null => { + bail!("parse_parameter_strings: internal error - schema contains Null."); + } + Jss::Boolean(jss_boolean) => { + let res = match value_str.to_lowercase().as_str() { + "1" | "on" | "yes" | "true" => true, + "0" | "off" | "no" | "false" => false, + _ => bail!("Unable to parse boolean option."), + }; + Value::Bool(res) + } + Jss::Integer(jss_integer) => { + let res: isize = value_str.parse()?; + Value::Number(res.into()) + } + Jss::String(jss_string) => { + Value::String(value_str.into()) + } + _ => bail!("parse_simple_value: schema contains complex Objects."), + }; + Ok(value) +} + +pub fn parse_parameter_strings(data: &Vec<(String, String)>, schema: &Jss) -> Result> { println!("QUERY Strings {:?}", data); - Ok(json!(null)) + let mut params = json!({}); + + let mut errors: Vec = Vec::new(); + + match schema { + Jss::Object(JssObject { properties, additional_properties, .. }) => { + for (key, value) in data { + if let Some(prop_schema) = properties.get::(key) { + match prop_schema { + Jss::Object(_) => { + errors.push(format_err!("parameter {}: cant parse complex Objects.", key)); + } + Jss::Array(jss_array) => { + if params[key] == Value::Null { + params[key] = json!([]); + } + match params[key] { + Value::Array(ref mut array) => { + match parse_simple_value(value, &jss_array.items) { + Ok(res) => array.push(res), + Err(err) => errors.push(format_err!("parameter {}: {}", key, err)), + } + } + _ => errors.push(format_err!("parameter {}: expected array - type missmatch", key)), + } + } + _ => { + match parse_simple_value(value, prop_schema) { + Ok(res) => { + if params[key] == Value::Null { + params[key] = res; + } else { + errors.push(format_err!("parameter {}: duplicate parameter.", key)); + } + }, + Err(err) => errors.push(format_err!("parameter {}: {}", key, err)), + } + } + + } + } else { + if *additional_properties { + match params[key] { + Value::Null => { + params[key] = Value::String(value.to_owned()); + }, + Value::String(ref old) => { + params[key] = Value::Array( + vec![Value::String(old.to_owned()), Value::String(value.to_owned())]); + } + Value::Array(ref mut array) => { + array.push(Value::String(value.to_string())); + } + _ => errors.push(format_err!("parameter {}: expected array - type missmatch", key)), + } + } else { + errors.push(format_err!("parameter {}: schema does not allow additional properties.", key)); + } + } + } + } + _ => errors.push(format_err!("Got unexpected schema type in parse_parameter_strings.")), + + } + + if (errors.len() > 0) { + Err(errors) + } else { + Ok(params) + } } #[test] diff --git a/src/main.rs b/src/main.rs index 6213f357..04e4014a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -70,7 +70,13 @@ fn handle_request(req: Request) -> Response { match parse_parameter_strings(¶m_list, &api_method.parameters) { Ok(query) => query, - Err(err) => http_error!(NOT_FOUND, format!("Unable to parse query parameters '{}' - {}", data, err)), + Err(ref error_list) => { + let mut msg = String::from(""); + for item in error_list { + msg = msg + &item.to_string() + "\n"; + } + http_error!(BAD_REQUEST, msg); + } } } None => json!({}),