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.",
|
description: "This is a simple test.",
|
||||||
parameters: parameter!{
|
parameters: parameter!{
|
||||||
force => Boolean!{
|
force => Boolean!{
|
||||||
optional => Some(true),
|
optional => true,
|
||||||
description => "Test for boolean options."
|
description => "Test for boolean options."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,23 +7,23 @@ pub type PropertyMap = HashMap<&'static str, Jss>;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct JssBoolean {
|
pub struct JssBoolean {
|
||||||
pub description: &'static str,
|
pub description: &'static str,
|
||||||
pub optional: Option<bool>,
|
pub optional: bool,
|
||||||
pub default: Option<bool>,
|
pub default: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct JssInteger {
|
pub struct JssInteger {
|
||||||
pub description: &'static str,
|
pub description: &'static str,
|
||||||
pub optional: Option<bool>,
|
pub optional: bool,
|
||||||
pub minimum: Option<usize>,
|
pub minimum: Option<isize>,
|
||||||
pub maximum: Option<usize>,
|
pub maximum: Option<isize>,
|
||||||
pub default: Option<usize>,
|
pub default: Option<isize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct JssString {
|
pub struct JssString {
|
||||||
pub description: &'static str,
|
pub description: &'static str,
|
||||||
pub optional: Option<bool>,
|
pub optional: bool,
|
||||||
pub default: Option<&'static str>,
|
pub default: Option<&'static str>,
|
||||||
pub min_length: Option<usize>,
|
pub min_length: Option<usize>,
|
||||||
pub max_length: Option<usize>,
|
pub max_length: Option<usize>,
|
||||||
|
@ -32,15 +32,15 @@ pub struct JssString {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct JssArray {
|
pub struct JssArray {
|
||||||
pub description: &'static str,
|
pub description: &'static str,
|
||||||
pub optional: Option<bool>,
|
pub optional: bool,
|
||||||
pub items: Box<Jss>,
|
pub items: Box<Jss>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct JssObject {
|
pub struct JssObject {
|
||||||
pub description: &'static str,
|
pub description: &'static str,
|
||||||
pub optional: Option<bool>,
|
pub optional: bool,
|
||||||
pub additional_properties: Option<bool>,
|
pub additional_properties: bool,
|
||||||
pub properties: HashMap<&'static str, Jss>,
|
pub properties: HashMap<&'static str, Jss>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ pub enum Jss {
|
||||||
|
|
||||||
pub const DEFAULTBOOL: JssBoolean = JssBoolean {
|
pub const DEFAULTBOOL: JssBoolean = JssBoolean {
|
||||||
description: "",
|
description: "",
|
||||||
optional: None,
|
optional: false,
|
||||||
default: None,
|
default: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ macro_rules! Boolean {
|
||||||
|
|
||||||
pub const DEFAULTINTEGER: JssInteger = JssInteger {
|
pub const DEFAULTINTEGER: JssInteger = JssInteger {
|
||||||
description: "",
|
description: "",
|
||||||
optional: None,
|
optional: false,
|
||||||
default: None,
|
default: None,
|
||||||
minimum: None,
|
minimum: None,
|
||||||
maximum: None,
|
maximum: None,
|
||||||
|
@ -84,7 +84,7 @@ macro_rules! Integer {
|
||||||
|
|
||||||
pub const DEFAULTSTRING: JssString = JssString {
|
pub const DEFAULTSTRING: JssString = JssString {
|
||||||
description: "",
|
description: "",
|
||||||
optional: None,
|
optional: false,
|
||||||
default: None,
|
default: None,
|
||||||
min_length: None,
|
min_length: None,
|
||||||
max_length: None,
|
max_length: None,
|
||||||
|
@ -102,8 +102,8 @@ macro_rules! parameter {
|
||||||
($($name:ident => $e:expr),*) => {{
|
($($name:ident => $e:expr),*) => {{
|
||||||
let inner = JssObject {
|
let inner = JssObject {
|
||||||
description: "",
|
description: "",
|
||||||
optional: None,
|
optional: false,
|
||||||
additional_properties: None,
|
additional_properties: false,
|
||||||
properties: {
|
properties: {
|
||||||
let mut map = HashMap::<&'static str, Jss>::new();
|
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);
|
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]
|
#[test]
|
||||||
|
|
|
@ -70,7 +70,13 @@ fn handle_request(req: Request<Body>) -> Response<Body> {
|
||||||
|
|
||||||
match parse_parameter_strings(¶m_list, &api_method.parameters) {
|
match parse_parameter_strings(¶m_list, &api_method.parameters) {
|
||||||
Ok(query) => query,
|
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!({}),
|
None => json!({}),
|
||||||
|
|
Loading…
Reference in New Issue