implement simple schema parser
This commit is contained in:
parent
42d569c186
commit
cfa5886c33
|
@ -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."
|
||||
}
|
||||
},
|
||||
|
|
|
@ -7,23 +7,23 @@ pub type PropertyMap = HashMap<&'static str, Jss>;
|
|||
#[derive(Debug)]
|
||||
pub struct JssBoolean {
|
||||
pub description: &'static str,
|
||||
pub optional: Option<bool>,
|
||||
pub optional: bool,
|
||||
pub default: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct JssInteger {
|
||||
pub description: &'static str,
|
||||
pub optional: Option<bool>,
|
||||
pub minimum: Option<usize>,
|
||||
pub maximum: Option<usize>,
|
||||
pub default: Option<usize>,
|
||||
pub optional: bool,
|
||||
pub minimum: Option<isize>,
|
||||
pub maximum: Option<isize>,
|
||||
pub default: Option<isize>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct JssString {
|
||||
pub description: &'static str,
|
||||
pub optional: Option<bool>,
|
||||
pub optional: bool,
|
||||
pub default: Option<&'static str>,
|
||||
pub min_length: Option<usize>,
|
||||
pub max_length: Option<usize>,
|
||||
|
@ -32,15 +32,15 @@ pub struct JssString {
|
|||
#[derive(Debug)]
|
||||
pub struct JssArray {
|
||||
pub description: &'static str,
|
||||
pub optional: Option<bool>,
|
||||
pub optional: bool,
|
||||
pub items: Box<Jss>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct JssObject {
|
||||
pub description: &'static str,
|
||||
pub optional: Option<bool>,
|
||||
pub additional_properties: Option<bool>,
|
||||
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<Value, Error> {
|
||||
|
||||
pub fn parse_parameter_strings(data: &Vec<(String, String)>, schema: &Jss) -> Result<Value, Error> {
|
||||
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<Value, Vec<Error>> {
|
||||
|
||||
println!("QUERY Strings {:?}", data);
|
||||
|
||||
Ok(json!(null))
|
||||
let mut params = json!({});
|
||||
|
||||
let mut errors: Vec<Error> = Vec::new();
|
||||
|
||||
match schema {
|
||||
Jss::Object(JssObject { properties, additional_properties, .. }) => {
|
||||
for (key, value) in data {
|
||||
if let Some(prop_schema) = properties.get::<str>(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]
|
||||
|
|
|
@ -70,7 +70,13 @@ fn handle_request(req: Request<Body>) -> Response<Body> {
|
|||
|
||||
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!({}),
|
||||
|
|
Loading…
Reference in New Issue