remove parameter macro, implement ObjectSchema builder
And store "optional" attribute inside properties hash.
This commit is contained in:
parent
82df76fff0
commit
7edeec7b06
|
@ -71,8 +71,7 @@ impl Registry {
|
|||
"pve-vmid",
|
||||
IntegerSchema::new("The (unique) ID of the VM.")
|
||||
.minimum(1)
|
||||
.optional(false)
|
||||
);
|
||||
);
|
||||
|
||||
self.register_option(
|
||||
"pve-node",
|
||||
|
|
|
@ -41,7 +41,6 @@ impl fmt::Display for ParameterError {
|
|||
#[derive(Debug)]
|
||||
pub struct BooleanSchema {
|
||||
pub description: &'static str,
|
||||
pub optional: bool,
|
||||
pub default: Option<bool>,
|
||||
}
|
||||
|
||||
|
@ -50,16 +49,10 @@ impl BooleanSchema {
|
|||
pub fn new(description: &'static str) -> Self {
|
||||
BooleanSchema {
|
||||
description: description,
|
||||
optional: false,
|
||||
default: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn optional(mut self, optional: bool) -> Self {
|
||||
self.optional = optional;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn default(mut self, default: bool) -> Self {
|
||||
self.default = Some(default);
|
||||
self
|
||||
|
@ -73,7 +66,6 @@ impl BooleanSchema {
|
|||
#[derive(Debug)]
|
||||
pub struct IntegerSchema {
|
||||
pub description: &'static str,
|
||||
pub optional: bool,
|
||||
pub minimum: Option<isize>,
|
||||
pub maximum: Option<isize>,
|
||||
pub default: Option<isize>,
|
||||
|
@ -84,18 +76,12 @@ impl IntegerSchema {
|
|||
pub fn new(description: &'static str) -> Self {
|
||||
IntegerSchema {
|
||||
description: description,
|
||||
optional: false,
|
||||
default: None,
|
||||
minimum: None,
|
||||
maximum: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn optional(mut self, optional: bool) -> Self {
|
||||
self.optional = optional;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn default(mut self, default: isize) -> Self {
|
||||
self.default = Some(default);
|
||||
self
|
||||
|
@ -120,7 +106,6 @@ impl IntegerSchema {
|
|||
#[derive(Debug)]
|
||||
pub struct StringSchema {
|
||||
pub description: &'static str,
|
||||
pub optional: bool,
|
||||
pub default: Option<&'static str>,
|
||||
pub min_length: Option<usize>,
|
||||
pub max_length: Option<usize>,
|
||||
|
@ -132,7 +117,6 @@ impl StringSchema {
|
|||
pub fn new(description: &'static str) -> Self {
|
||||
StringSchema {
|
||||
description: description,
|
||||
optional: false,
|
||||
default: None,
|
||||
min_length: None,
|
||||
max_length: None,
|
||||
|
@ -140,11 +124,6 @@ impl StringSchema {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn optional(mut self, optional: bool) -> Self {
|
||||
self.optional = optional;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn default(mut self, text: &'static str) -> Self {
|
||||
self.default = Some(text);
|
||||
self
|
||||
|
@ -173,16 +152,45 @@ impl StringSchema {
|
|||
#[derive(Debug)]
|
||||
pub struct ArraySchema {
|
||||
pub description: &'static str,
|
||||
pub optional: bool,
|
||||
pub items: Arc<Schema>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ObjectSchema {
|
||||
pub description: &'static str,
|
||||
pub optional: bool,
|
||||
pub additional_properties: bool,
|
||||
pub properties: HashMap<&'static str, Arc<Schema>>,
|
||||
pub properties: HashMap<&'static str, (bool, Arc<Schema>)>,
|
||||
}
|
||||
|
||||
impl ObjectSchema {
|
||||
|
||||
pub fn new(description: &'static str) -> Self {
|
||||
let properties = HashMap::new();
|
||||
ObjectSchema {
|
||||
description: description,
|
||||
additional_properties: false,
|
||||
properties: properties,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn additional_properties(mut self, additional_properties: bool) -> Self {
|
||||
self.additional_properties = additional_properties;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn required(mut self, name: &'static str, schema: Arc<Schema>) -> Self {
|
||||
self.properties.insert(name, (false, schema));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn optional(mut self, name: &'static str, schema: Arc<Schema>) -> Self {
|
||||
self.properties.insert(name, (true, schema));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn arc(self) -> Arc<Schema> {
|
||||
Arc::new(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -213,6 +221,12 @@ impl From<IntegerSchema> for Schema {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<ObjectSchema> for Schema {
|
||||
fn from(object_schema: ObjectSchema) -> Self {
|
||||
Schema::Object(object_schema)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ApiStringFormat {
|
||||
Enum(Vec<String>),
|
||||
Pattern(Box<Regex>),
|
||||
|
@ -239,33 +253,6 @@ impl std::fmt::Debug for ApiStringFormat {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! parameter {
|
||||
() => {{
|
||||
ObjectSchema {
|
||||
description: "",
|
||||
optional: false,
|
||||
additional_properties: false,
|
||||
properties: HashMap::<&'static str, Arc<Schema>>::new(),
|
||||
}
|
||||
}};
|
||||
($($name:ident => $e:expr),*) => {{
|
||||
ObjectSchema {
|
||||
description: "",
|
||||
optional: false,
|
||||
additional_properties: false,
|
||||
properties: {
|
||||
let mut map = HashMap::<&'static str, Arc<Schema>>::new();
|
||||
$(
|
||||
map.insert(stringify!($name), $e);
|
||||
)*
|
||||
map
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
pub fn parse_boolean(value_str: &str) -> Result<bool, Error> {
|
||||
match value_str.to_lowercase().as_str() {
|
||||
"1" | "on" | "yes" | "true" => Ok(true),
|
||||
|
@ -357,7 +344,7 @@ pub fn parse_parameter_strings(data: &Vec<(String, String)>, schema: &ObjectSche
|
|||
let additional_properties = schema.additional_properties;
|
||||
|
||||
for (key, value) in data {
|
||||
if let Some(prop_schema) = properties.get::<str>(key) {
|
||||
if let Some((_optional, prop_schema)) = properties.get::<str>(key) {
|
||||
match prop_schema.as_ref() {
|
||||
Schema::Array(array_schema) => {
|
||||
if params[key] == Value::Null {
|
||||
|
@ -408,16 +395,8 @@ pub fn parse_parameter_strings(data: &Vec<(String, String)>, schema: &ObjectSche
|
|||
}
|
||||
|
||||
if test_required && errors.len() == 0 {
|
||||
for (name, prop_schema) in properties {
|
||||
let optional = match prop_schema.as_ref() {
|
||||
Schema::Boolean(boolean_schema) => boolean_schema.optional,
|
||||
Schema::Integer(integer_schema) => integer_schema.optional,
|
||||
Schema::String(string_schema) => string_schema.optional,
|
||||
Schema::Array(array_schema) => array_schema.optional,
|
||||
Schema::Object(object_schema) => object_schema.optional,
|
||||
Schema::Null => true,
|
||||
};
|
||||
if optional == false && params[name] == Value::Null {
|
||||
for (name, (optional, _prop_schema)) in properties {
|
||||
if *optional == false && params[name] == Value::Null {
|
||||
errors.push(format_err!("parameter '{}': parameter is missing and it is not optional.", name));
|
||||
}
|
||||
}
|
||||
|
@ -442,7 +421,6 @@ pub fn parse_query_string(query: &str, schema: &ObjectSchema, test_required: boo
|
|||
fn test_schema1() {
|
||||
let schema = Schema::Object(ObjectSchema {
|
||||
description: "TEST",
|
||||
optional: false,
|
||||
additional_properties: false,
|
||||
properties: {
|
||||
let map = HashMap::new();
|
||||
|
@ -457,25 +435,27 @@ fn test_schema1() {
|
|||
#[test]
|
||||
fn test_query_string() {
|
||||
|
||||
let schema = parameter!{name => StringSchema::new("Name.").optional(false).arc()};
|
||||
let schema = ObjectSchema::new("Parameters.")
|
||||
.required("name", StringSchema::new("Name.").arc());
|
||||
|
||||
let res = parse_query_string("", &schema, true);
|
||||
assert!(res.is_err());
|
||||
|
||||
let schema = parameter!{name => StringSchema::new("Name.").optional(true).arc()};
|
||||
let schema = ObjectSchema::new("Parameters.")
|
||||
.optional("name", StringSchema::new("Name.").arc());
|
||||
|
||||
let res = parse_query_string("", &schema, true);
|
||||
assert!(res.is_ok());
|
||||
|
||||
// TEST min_length and max_length
|
||||
|
||||
let schema = parameter!{
|
||||
name => StringSchema::new("Name.")
|
||||
.optional(false)
|
||||
.min_length(5)
|
||||
.max_length(10)
|
||||
.arc()
|
||||
};
|
||||
let schema = ObjectSchema::new("Parameters.")
|
||||
.required(
|
||||
"name", StringSchema::new("Name.")
|
||||
.min_length(5)
|
||||
.max_length(10)
|
||||
.arc()
|
||||
);
|
||||
|
||||
let res = parse_query_string("name=abcd", &schema, true);
|
||||
assert!(res.is_err());
|
||||
|
@ -491,12 +471,12 @@ fn test_query_string() {
|
|||
|
||||
// TEST regex pattern
|
||||
|
||||
let schema = parameter!{
|
||||
name => StringSchema::new("Name.")
|
||||
.optional(false)
|
||||
.format(Arc::new(ApiStringFormat::Pattern(Box::new(Regex::new("test").unwrap()))))
|
||||
.arc()
|
||||
};
|
||||
let schema = ObjectSchema::new("Parameters.")
|
||||
.required(
|
||||
"name", StringSchema::new("Name.")
|
||||
.format(Arc::new(ApiStringFormat::Pattern(Box::new(Regex::new("test").unwrap()))))
|
||||
.arc()
|
||||
);
|
||||
|
||||
let res = parse_query_string("name=abcd", &schema, true);
|
||||
assert!(res.is_err());
|
||||
|
@ -504,12 +484,12 @@ fn test_query_string() {
|
|||
let res = parse_query_string("name=ateststring", &schema, true);
|
||||
assert!(res.is_ok());
|
||||
|
||||
let schema = parameter!{
|
||||
name => StringSchema::new("Name.")
|
||||
.optional(false)
|
||||
.format(Arc::new(ApiStringFormat::Pattern(Box::new(Regex::new("^test$").unwrap()))))
|
||||
.arc()
|
||||
};
|
||||
let schema = ObjectSchema::new("Parameters.")
|
||||
.required(
|
||||
"name", StringSchema::new("Name.")
|
||||
.format(Arc::new(ApiStringFormat::Pattern(Box::new(Regex::new("^test$").unwrap()))))
|
||||
.arc()
|
||||
);
|
||||
|
||||
let res = parse_query_string("name=ateststring", &schema, true);
|
||||
assert!(res.is_err());
|
||||
|
@ -519,12 +499,12 @@ fn test_query_string() {
|
|||
|
||||
// TEST string enums
|
||||
|
||||
let schema = parameter!{
|
||||
name => StringSchema::new("Name.")
|
||||
.optional(false)
|
||||
.format(Arc::new(ApiStringFormat::Enum(vec!["ev1".into(), "ev2".into()])))
|
||||
.arc()
|
||||
};
|
||||
let schema = ObjectSchema::new("Parameters.")
|
||||
.required(
|
||||
"name", StringSchema::new("Name.")
|
||||
.format(Arc::new(ApiStringFormat::Enum(vec!["ev1".into(), "ev2".into()])))
|
||||
.arc()
|
||||
);
|
||||
|
||||
let res = parse_query_string("name=noenum", &schema, true);
|
||||
assert!(res.is_err());
|
||||
|
@ -543,18 +523,22 @@ fn test_query_string() {
|
|||
#[test]
|
||||
fn test_query_integer() {
|
||||
|
||||
let schema = parameter!{count => IntegerSchema::new("Count.").optional(false).arc()};
|
||||
let schema = ObjectSchema::new("Parameters.")
|
||||
.required(
|
||||
"count" , IntegerSchema::new("Count.")
|
||||
.arc()
|
||||
);
|
||||
|
||||
let res = parse_query_string("", &schema, true);
|
||||
assert!(res.is_err());
|
||||
|
||||
let schema = parameter!{
|
||||
count => IntegerSchema::new("Count.")
|
||||
.optional(true)
|
||||
.minimum(-3)
|
||||
.maximum(50)
|
||||
.arc()
|
||||
};
|
||||
let schema = ObjectSchema::new("Parameters.")
|
||||
.optional(
|
||||
"count", IntegerSchema::new("Count.")
|
||||
.minimum(-3)
|
||||
.maximum(50)
|
||||
.arc()
|
||||
);
|
||||
|
||||
let res = parse_query_string("", &schema, true);
|
||||
assert!(res.is_ok());
|
||||
|
@ -584,12 +568,20 @@ fn test_query_integer() {
|
|||
#[test]
|
||||
fn test_query_boolean() {
|
||||
|
||||
let schema = parameter!{force => BooleanSchema::new("Force.").optional(false).arc()};
|
||||
let schema = ObjectSchema::new("Parameters.")
|
||||
.required(
|
||||
"force", BooleanSchema::new("Force.")
|
||||
.arc()
|
||||
);
|
||||
|
||||
let res = parse_query_string("", &schema, true);
|
||||
assert!(res.is_err());
|
||||
|
||||
let schema = parameter!{force => BooleanSchema::new("Force.").optional(true).arc()};
|
||||
let schema = ObjectSchema::new("Parameters.")
|
||||
.optional(
|
||||
"force", BooleanSchema::new("Force.")
|
||||
.arc()
|
||||
);
|
||||
|
||||
let res = parse_query_string("", &schema, true);
|
||||
assert!(res.is_ok());
|
||||
|
|
13
src/api3.rs
13
src/api3.rs
|
@ -31,7 +31,7 @@ pub fn router() -> Router {
|
|||
let route3 = Router::new()
|
||||
.get(ApiMethod {
|
||||
description: "Another Endpoint.",
|
||||
parameters: parameter!{},
|
||||
parameters: ObjectSchema::new("Another Endpoint."),
|
||||
returns: Schema::Null,
|
||||
handler: |param, _info| {
|
||||
println!("This is a clousure handler: {}", param);
|
||||
|
@ -44,11 +44,12 @@ pub fn router() -> Router {
|
|||
.get(ApiMethod {
|
||||
handler: test_sync_api_handler,
|
||||
description: "This is a simple test.",
|
||||
parameters: parameter!{
|
||||
force => BooleanSchema::new("Test for boolean options")
|
||||
.optional(true)
|
||||
.arc()
|
||||
},
|
||||
parameters: ObjectSchema::new("This is a simple test.")
|
||||
.optional(
|
||||
"force",
|
||||
BooleanSchema::new("Test for boolean options")
|
||||
.arc()
|
||||
),
|
||||
returns: Schema::Null,
|
||||
})
|
||||
.subdirs({
|
||||
|
|
|
@ -75,7 +75,7 @@ pub fn parse_arguments(
|
|||
None => {
|
||||
let mut want_bool = false;
|
||||
let mut can_default = false;
|
||||
if let Some(param_schema) = properties.get::<str>(&name) {
|
||||
if let Some((_optional, param_schema)) = properties.get::<str>(&name) {
|
||||
if let Schema::Boolean(boolean_schema) = param_schema.as_ref() {
|
||||
want_bool = true;
|
||||
if let Some(default) = boolean_schema.default {
|
||||
|
@ -156,7 +156,11 @@ pub fn parse_arguments(
|
|||
#[test]
|
||||
fn test_boolean_arg() {
|
||||
|
||||
let schema = parameter!{enable => BooleanSchema::new("Enable").optional(false).arc()};
|
||||
let schema = ObjectSchema::new("Parameters:")
|
||||
.required(
|
||||
"enable", BooleanSchema::new("Enable")
|
||||
.arc()
|
||||
);
|
||||
|
||||
let mut variants: Vec<(Vec<&str>, bool)> = vec![];
|
||||
variants.push((vec!["-enable"], true));
|
||||
|
@ -186,10 +190,9 @@ fn test_boolean_arg() {
|
|||
#[test]
|
||||
fn test_argument_paramenter() {
|
||||
|
||||
let schema = parameter!{
|
||||
enable => BooleanSchema::new("Enable.").optional(false).arc(),
|
||||
storage => StringSchema::new("Storatge:").optional(false).arc()
|
||||
};
|
||||
let schema = ObjectSchema::new("Parameters:")
|
||||
.required("enable", BooleanSchema::new("Enable.").arc())
|
||||
.required("storage", StringSchema::new("Storage.").arc());
|
||||
|
||||
let args = vec!["-enable", "local"];
|
||||
let string_args = args.iter().map(|s| s.to_string()).collect();
|
||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -1,9 +1,5 @@
|
|||
#[macro_use]
|
||||
extern crate apitest;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use apitest::api::schema::*;
|
||||
use apitest::api::router::*;
|
||||
use apitest::api::config::*;
|
||||
|
@ -23,10 +19,9 @@ fn main() {
|
|||
let prop = StringSchema::new("This is a test").arc();
|
||||
|
||||
//let prop = Arc::new(ApiString!{ optional => true });
|
||||
let schema = parameter!{
|
||||
name1 => prop.clone(),
|
||||
name2 => prop.clone()
|
||||
};
|
||||
let schema = ObjectSchema::new("Parameters.")
|
||||
.required("name1", prop.clone())
|
||||
.required("name2", prop.clone());
|
||||
|
||||
let args: Vec<String> = std::env::args().skip(1).collect();
|
||||
match getopts::parse_arguments(&args, &vec![], &schema) {
|
||||
|
|
Loading…
Reference in New Issue