forked from proxmox-mirrors/proxmox
		
	schema: make verification functions methods
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
		
							parent
							
								
									fbd82c81d1
								
							
						
					
					
						commit
						efe492034e
					
				| @ -101,6 +101,14 @@ impl BooleanSchema { | ||||
|     pub const fn schema(self) -> Schema { | ||||
|         Schema::Boolean(self) | ||||
|     } | ||||
| 
 | ||||
|     /// Verify JSON value using a `BooleanSchema`.
 | ||||
|     pub fn verify_json(&self, data: &Value) -> Result<(), Error> { | ||||
|         if !data.is_boolean() { | ||||
|             bail!("Expected boolean value."); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Data type to describe integer values.
 | ||||
| @ -168,6 +176,15 @@ impl IntegerSchema { | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     /// Verify JSON value using an `IntegerSchema`.
 | ||||
|     pub fn verify_json(&self, data: &Value) -> Result<(), Error> { | ||||
|         if let Some(value) = data.as_i64() { | ||||
|             self.check_constraints(value as isize) | ||||
|         } else { | ||||
|             bail!("Expected integer value."); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Data type to describe (JSON like) number value
 | ||||
| @ -234,6 +251,15 @@ impl NumberSchema { | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     /// Verify JSON value using an `NumberSchema`.
 | ||||
|     pub fn verify_json(&self, data: &Value) -> Result<(), Error> { | ||||
|         if let Some(value) = data.as_f64() { | ||||
|             self.check_constraints(value) | ||||
|         } else { | ||||
|             bail!("Expected number value."); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(feature = "test-harness")] | ||||
| @ -347,7 +373,7 @@ impl StringSchema { | ||||
|                     } | ||||
|                 } | ||||
|                 ApiStringFormat::PropertyString(subschema) => { | ||||
|                     parse_property_string(value, subschema)?; | ||||
|                     subschema.parse_property_string(value)?; | ||||
|                 } | ||||
|                 ApiStringFormat::VerifyFn(verify_fn) => { | ||||
|                     verify_fn(value)?; | ||||
| @ -357,6 +383,15 @@ impl StringSchema { | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     /// Verify JSON value using this `StringSchema`.
 | ||||
|     pub fn verify_json(&self, data: &Value) -> Result<(), Error> { | ||||
|         if let Some(value) = data.as_str() { | ||||
|             self.check_constraints(value) | ||||
|         } else { | ||||
|             bail!("Expected string value."); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Data type to describe array of values.
 | ||||
| @ -414,6 +449,28 @@ impl ArraySchema { | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     /// Verify JSON value using an `ArraySchema`.
 | ||||
|     pub fn verify_json(&self, data: &Value) -> Result<(), Error> { | ||||
|         let list = match data { | ||||
|             Value::Array(ref list) => list, | ||||
|             Value::Object(_) => bail!("Expected array - got object."), | ||||
|             _ => bail!("Expected array - got scalar value."), | ||||
|         }; | ||||
| 
 | ||||
|         self.check_length(list.len())?; | ||||
| 
 | ||||
|         for (i, item) in list.iter().enumerate() { | ||||
|             let result = self.items.verify_json(item); | ||||
|             if let Err(err) = result { | ||||
|                 let mut errors = ParameterError::new(); | ||||
|                 errors.add_errors(&format!("[{}]", i), err); | ||||
|                 return Err(errors.into()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Property entry in an object schema:
 | ||||
| @ -486,6 +543,18 @@ impl ObjectSchema { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Parse key/value pairs and verify with object schema
 | ||||
|     ///
 | ||||
|     /// - `test_required`: is set, checks if all required properties are
 | ||||
|     ///   present.
 | ||||
|     pub fn parse_parameter_strings( | ||||
|         &'static self, | ||||
|         data: &[(String, String)], | ||||
|         test_required: bool, | ||||
|     ) -> Result<Value, ParameterError> { | ||||
|         ParameterSchema::from(self).parse_parameter_strings(data, test_required) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Combines multiple *object* schemas into one.
 | ||||
| @ -532,6 +601,18 @@ impl AllOfSchema { | ||||
| 
 | ||||
|         None | ||||
|     } | ||||
| 
 | ||||
|     /// Parse key/value pairs and verify with object schema
 | ||||
|     ///
 | ||||
|     /// - `test_required`: is set, checks if all required properties are
 | ||||
|     ///   present.
 | ||||
|     pub fn parse_parameter_strings( | ||||
|         &'static self, | ||||
|         data: &[(String, String)], | ||||
|         test_required: bool, | ||||
|     ) -> Result<Value, ParameterError> { | ||||
|         ParameterSchema::from(self).parse_parameter_strings(data, test_required) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Beside [`ObjectSchema`] we also have an [`AllOfSchema`] which also represents objects.
 | ||||
| @ -540,6 +621,47 @@ pub trait ObjectSchemaType { | ||||
|     fn lookup(&self, key: &str) -> Option<(bool, &Schema)>; | ||||
|     fn properties(&self) -> ObjectPropertyIterator; | ||||
|     fn additional_properties(&self) -> bool; | ||||
| 
 | ||||
|     /// Verify JSON value using an object schema.
 | ||||
|     fn verify_json(&self, data: &Value) -> Result<(), Error> { | ||||
|         let map = match data { | ||||
|             Value::Object(ref map) => map, | ||||
|             Value::Array(_) => bail!("Expected object - got array."), | ||||
|             _ => bail!("Expected object - got scalar value."), | ||||
|         }; | ||||
| 
 | ||||
|         let mut errors = ParameterError::new(); | ||||
| 
 | ||||
|         let additional_properties = self.additional_properties(); | ||||
| 
 | ||||
|         for (key, value) in map { | ||||
|             if let Some((_optional, prop_schema)) = self.lookup(key) { | ||||
|                 if let Err(err) = prop_schema.verify_json(value) { | ||||
|                     errors.add_errors(key, err); | ||||
|                 }; | ||||
|             } else if !additional_properties { | ||||
|                 errors.push( | ||||
|                     key.to_string(), | ||||
|                     format_err!("schema does not allow additional properties."), | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         for (name, optional, _prop_schema) in self.properties() { | ||||
|             if !(*optional) && data[name] == Value::Null { | ||||
|                 errors.push( | ||||
|                     name.to_string(), | ||||
|                     format_err!("property is missing and it is not optional."), | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if !errors.is_empty() { | ||||
|             Err(errors.into()) | ||||
|         } else { | ||||
|             Ok(()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl ObjectSchemaType for ObjectSchema { | ||||
| @ -660,6 +782,109 @@ pub enum Schema { | ||||
|     AllOf(AllOfSchema), | ||||
| } | ||||
| 
 | ||||
| impl Schema { | ||||
|     /// Verify JSON value with `schema`.
 | ||||
|     pub fn verify_json(&self, data: &Value) -> Result<(), Error> { | ||||
|         match self { | ||||
|             Schema::Null => { | ||||
|                 if !data.is_null() { | ||||
|                     bail!("Expected Null, but value is not Null."); | ||||
|                 } | ||||
|             } | ||||
|             Schema::Object(s) => s.verify_json(data)?, | ||||
|             Schema::Array(s) => s.verify_json(data)?, | ||||
|             Schema::Boolean(s) => s.verify_json(data)?, | ||||
|             Schema::Integer(s) => s.verify_json(data)?, | ||||
|             Schema::Number(s) => s.verify_json(data)?, | ||||
|             Schema::String(s) => s.verify_json(data)?, | ||||
|             Schema::AllOf(s) => s.verify_json(data)?, | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     /// Parse a simple value (no arrays and no objects)
 | ||||
|     pub fn parse_simple_value(&self, value_str: &str) -> Result<Value, Error> { | ||||
|         let value = match self { | ||||
|             Schema::Null => { | ||||
|                 bail!("internal error - found Null schema."); | ||||
|             } | ||||
|             Schema::Boolean(_boolean_schema) => { | ||||
|                 let res = parse_boolean(value_str)?; | ||||
|                 Value::Bool(res) | ||||
|             } | ||||
|             Schema::Integer(integer_schema) => { | ||||
|                 let res: isize = value_str.parse()?; | ||||
|                 integer_schema.check_constraints(res)?; | ||||
|                 Value::Number(res.into()) | ||||
|             } | ||||
|             Schema::Number(number_schema) => { | ||||
|                 let res: f64 = value_str.parse()?; | ||||
|                 number_schema.check_constraints(res)?; | ||||
|                 Value::Number(serde_json::Number::from_f64(res).unwrap()) | ||||
|             } | ||||
|             Schema::String(string_schema) => { | ||||
|                 string_schema.check_constraints(value_str)?; | ||||
|                 Value::String(value_str.into()) | ||||
|             } | ||||
|             _ => bail!("unable to parse complex (sub) objects."), | ||||
|         }; | ||||
|         Ok(value) | ||||
|     } | ||||
| 
 | ||||
|     /// Parse a complex property string (`ApiStringFormat::PropertyString`)
 | ||||
|     pub fn parse_property_string(&'static self, value_str: &str) -> Result<Value, Error> { | ||||
|         // helper for object/allof schemas:
 | ||||
|         fn parse_object<T: Into<ParameterSchema>>( | ||||
|             value_str: &str, | ||||
|             schema: T, | ||||
|             default_key: Option<&'static str>, | ||||
|         ) -> Result<Value, Error> { | ||||
|             let mut param_list: Vec<(String, String)> = vec![]; | ||||
|             let key_val_list: Vec<&str> = value_str | ||||
|                 .split(|c: char| c == ',' || c == ';') | ||||
|                 .filter(|s| !s.is_empty()) | ||||
|                 .collect(); | ||||
|             for key_val in key_val_list { | ||||
|                 let kv: Vec<&str> = key_val.splitn(2, '=').collect(); | ||||
|                 if kv.len() == 2 { | ||||
|                     param_list.push((kv[0].trim().into(), kv[1].trim().into())); | ||||
|                 } else if let Some(key) = default_key { | ||||
|                     param_list.push((key.into(), kv[0].trim().into())); | ||||
|                 } else { | ||||
|                     bail!("Value without key, but schema does not define a default key."); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             schema.into().parse_parameter_strings(¶m_list, true).map_err(Error::from) | ||||
|         } | ||||
| 
 | ||||
|         match self { | ||||
|             Schema::Object(object_schema) => { | ||||
|                 parse_object(value_str, object_schema, object_schema.default_key) | ||||
|             } | ||||
|             Schema::AllOf(all_of_schema) => parse_object(value_str, all_of_schema, None), | ||||
|             Schema::Array(array_schema) => { | ||||
|                 let mut array: Vec<Value> = vec![]; | ||||
|                 let list: Vec<&str> = value_str | ||||
|                     .split(|c: char| c == ',' || c == ';' || char::is_ascii_whitespace(&c)) | ||||
|                     .filter(|s| !s.is_empty()) | ||||
|                     .collect(); | ||||
| 
 | ||||
|                 for value in list { | ||||
|                     match array_schema.items.parse_simple_value(value.trim()) { | ||||
|                         Ok(res) => array.push(res), | ||||
|                         Err(err) => bail!("unable to parse array element: {}", err), | ||||
|                     } | ||||
|                 } | ||||
|                 array_schema.check_length(array.len())?; | ||||
| 
 | ||||
|                 Ok(array.into()) | ||||
|             } | ||||
|             _ => bail!("Got unexpected schema type."), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// A string enum entry. An enum entry must have a value and a description.
 | ||||
| #[derive(Clone, Debug)] | ||||
| #[cfg_attr(feature = "test-harness", derive(Eq, PartialEq))] | ||||
| @ -791,6 +1016,20 @@ pub enum ParameterSchema { | ||||
|     AllOf(&'static AllOfSchema), | ||||
| } | ||||
| 
 | ||||
| impl ParameterSchema { | ||||
|     /// Parse key/value pairs and verify with object schema
 | ||||
|     ///
 | ||||
|     /// - `test_required`: is set, checks if all required properties are
 | ||||
|     ///   present.
 | ||||
|     pub fn parse_parameter_strings( | ||||
|         self, | ||||
|         data: &[(String, String)], | ||||
|         test_required: bool, | ||||
|     ) -> Result<Value, ParameterError> { | ||||
|         do_parse_parameter_strings(self, data, test_required) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl ObjectSchemaType for ParameterSchema { | ||||
|     fn description(&self) -> &'static str { | ||||
|         match self { | ||||
| @ -846,102 +1085,33 @@ pub fn parse_boolean(value_str: &str) -> Result<bool, Error> { | ||||
| } | ||||
| 
 | ||||
| /// Parse a complex property string (`ApiStringFormat::PropertyString`)
 | ||||
| #[deprecated(note = "this is now a method of Schema")] | ||||
| pub fn parse_property_string(value_str: &str, schema: &'static Schema) -> Result<Value, Error> { | ||||
|     // helper for object/allof schemas:
 | ||||
|     fn parse_object<T: Into<ParameterSchema>>( | ||||
|         value_str: &str, | ||||
|         schema: T, | ||||
|         default_key: Option<&'static str>, | ||||
|     ) -> Result<Value, Error> { | ||||
|         let mut param_list: Vec<(String, String)> = vec![]; | ||||
|         let key_val_list: Vec<&str> = value_str | ||||
|             .split(|c: char| c == ',' || c == ';') | ||||
|             .filter(|s| !s.is_empty()) | ||||
|             .collect(); | ||||
|         for key_val in key_val_list { | ||||
|             let kv: Vec<&str> = key_val.splitn(2, '=').collect(); | ||||
|             if kv.len() == 2 { | ||||
|                 param_list.push((kv[0].trim().into(), kv[1].trim().into())); | ||||
|             } else if let Some(key) = default_key { | ||||
|                 param_list.push((key.into(), kv[0].trim().into())); | ||||
|             } else { | ||||
|                 bail!("Value without key, but schema does not define a default key."); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         parse_parameter_strings(¶m_list, schema, true).map_err(Error::from) | ||||
|     } | ||||
| 
 | ||||
|     match schema { | ||||
|         Schema::Object(object_schema) => { | ||||
|             parse_object(value_str, object_schema, object_schema.default_key) | ||||
|         } | ||||
|         Schema::AllOf(all_of_schema) => parse_object(value_str, all_of_schema, None), | ||||
|         Schema::Array(array_schema) => { | ||||
|             let mut array: Vec<Value> = vec![]; | ||||
|             let list: Vec<&str> = value_str | ||||
|                 .split(|c: char| c == ',' || c == ';' || char::is_ascii_whitespace(&c)) | ||||
|                 .filter(|s| !s.is_empty()) | ||||
|                 .collect(); | ||||
| 
 | ||||
|             for value in list { | ||||
|                 match parse_simple_value(value.trim(), array_schema.items) { | ||||
|                     Ok(res) => array.push(res), | ||||
|                     Err(err) => bail!("unable to parse array element: {}", err), | ||||
|                 } | ||||
|             } | ||||
|             array_schema.check_length(array.len())?; | ||||
| 
 | ||||
|             Ok(array.into()) | ||||
|         } | ||||
|         _ => bail!("Got unexpected schema type."), | ||||
|     } | ||||
|     schema.parse_property_string(value_str) | ||||
| } | ||||
| 
 | ||||
| /// Parse a simple value (no arrays and no objects)
 | ||||
| #[deprecated(note = "this is now a method of Schema")] | ||||
| pub fn parse_simple_value(value_str: &str, schema: &Schema) -> Result<Value, Error> { | ||||
|     let value = match schema { | ||||
|         Schema::Null => { | ||||
|             bail!("internal error - found Null schema."); | ||||
|         } | ||||
|         Schema::Boolean(_boolean_schema) => { | ||||
|             let res = parse_boolean(value_str)?; | ||||
|             Value::Bool(res) | ||||
|         } | ||||
|         Schema::Integer(integer_schema) => { | ||||
|             let res: isize = value_str.parse()?; | ||||
|             integer_schema.check_constraints(res)?; | ||||
|             Value::Number(res.into()) | ||||
|         } | ||||
|         Schema::Number(number_schema) => { | ||||
|             let res: f64 = value_str.parse()?; | ||||
|             number_schema.check_constraints(res)?; | ||||
|             Value::Number(serde_json::Number::from_f64(res).unwrap()) | ||||
|         } | ||||
|         Schema::String(string_schema) => { | ||||
|             string_schema.check_constraints(value_str)?; | ||||
|             Value::String(value_str.into()) | ||||
|         } | ||||
|         _ => bail!("unable to parse complex (sub) objects."), | ||||
|     }; | ||||
|     Ok(value) | ||||
|     schema.parse_simple_value(value_str) | ||||
| } | ||||
| 
 | ||||
| /// Parse key/value pairs and verify with object schema
 | ||||
| ///
 | ||||
| /// - `test_required`: is set, checks if all required properties are
 | ||||
| ///   present.
 | ||||
| #[deprecated(note = "this is now a method of parameter schema types")] | ||||
| pub fn parse_parameter_strings<T: Into<ParameterSchema>>( | ||||
|     data: &[(String, String)], | ||||
|     schema: T, | ||||
|     test_required: bool, | ||||
| ) -> Result<Value, ParameterError> { | ||||
|     do_parse_parameter_strings(data, schema.into(), test_required) | ||||
|     do_parse_parameter_strings(schema.into(), data, test_required) | ||||
| } | ||||
| 
 | ||||
| fn do_parse_parameter_strings( | ||||
|     data: &[(String, String)], | ||||
|     schema: ParameterSchema, | ||||
|     data: &[(String, String)], | ||||
|     test_required: bool, | ||||
| ) -> Result<Value, ParameterError> { | ||||
|     let mut params = json!({}); | ||||
| @ -959,7 +1129,7 @@ fn do_parse_parameter_strings( | ||||
|                     } | ||||
|                     match params[key] { | ||||
|                         Value::Array(ref mut array) => { | ||||
|                             match parse_simple_value(value, array_schema.items) { | ||||
|                             match array_schema.items.parse_simple_value(value) { | ||||
|                                 Ok(res) => array.push(res), // fixme: check_length??
 | ||||
|                                 Err(err) => errors.push(key.into(), err), | ||||
|                             } | ||||
| @ -969,7 +1139,7 @@ fn do_parse_parameter_strings( | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 _ => match parse_simple_value(value, prop_schema) { | ||||
|                 _ => match prop_schema.parse_simple_value(value) { | ||||
|                     Ok(res) => { | ||||
|                         if params[key] == Value::Null { | ||||
|                             params[key] = res; | ||||
| @ -1023,125 +1193,45 @@ fn do_parse_parameter_strings( | ||||
| } | ||||
| 
 | ||||
| /// Verify JSON value with `schema`.
 | ||||
| #[deprecated(note = "use the method schema.verify_json() instead")] | ||||
| pub fn verify_json(data: &Value, schema: &Schema) -> Result<(), Error> { | ||||
|     match schema { | ||||
|         Schema::Null => { | ||||
|             if !data.is_null() { | ||||
|                 bail!("Expected Null, but value is not Null."); | ||||
|             } | ||||
|         } | ||||
|         Schema::Object(object_schema) => verify_json_object(data, object_schema)?, | ||||
|         Schema::Array(array_schema) => verify_json_array(data, array_schema)?, | ||||
|         Schema::Boolean(boolean_schema) => verify_json_boolean(data, boolean_schema)?, | ||||
|         Schema::Integer(integer_schema) => verify_json_integer(data, integer_schema)?, | ||||
|         Schema::Number(number_schema) => verify_json_number(data, number_schema)?, | ||||
|         Schema::String(string_schema) => verify_json_string(data, string_schema)?, | ||||
|         Schema::AllOf(all_of_schema) => verify_json_object(data, all_of_schema)?, | ||||
|     } | ||||
|     Ok(()) | ||||
|     schema.verify_json(data) | ||||
| } | ||||
| 
 | ||||
| /// Verify JSON value using a `StringSchema`.
 | ||||
| #[deprecated(note = "use the method string_schema.verify_json() instead")] | ||||
| pub fn verify_json_string(data: &Value, schema: &StringSchema) -> Result<(), Error> { | ||||
|     if let Some(value) = data.as_str() { | ||||
|         schema.check_constraints(value) | ||||
|     } else { | ||||
|         bail!("Expected string value."); | ||||
|     } | ||||
|     schema.verify_json(data) | ||||
| } | ||||
| 
 | ||||
| /// Verify JSON value using a `BooleanSchema`.
 | ||||
| pub fn verify_json_boolean(data: &Value, _schema: &BooleanSchema) -> Result<(), Error> { | ||||
|     if !data.is_boolean() { | ||||
|         bail!("Expected boolean value."); | ||||
|     } | ||||
|     Ok(()) | ||||
| #[deprecated(note = "use the method boolean_schema.verify_json() instead")] | ||||
| pub fn verify_json_boolean(data: &Value, schema: &BooleanSchema) -> Result<(), Error> { | ||||
|     schema.verify_json(data) | ||||
| } | ||||
| 
 | ||||
| /// Verify JSON value using an `IntegerSchema`.
 | ||||
| #[deprecated(note = "use the method integer_schema.verify_json() instead")] | ||||
| pub fn verify_json_integer(data: &Value, schema: &IntegerSchema) -> Result<(), Error> { | ||||
|     if let Some(value) = data.as_i64() { | ||||
|         schema.check_constraints(value as isize) | ||||
|     } else { | ||||
|         bail!("Expected integer value."); | ||||
|     } | ||||
|     schema.verify_json(data) | ||||
| } | ||||
| 
 | ||||
| /// Verify JSON value using an `NumberSchema`.
 | ||||
| #[deprecated(note = "use the method number_schema.verify_json() instead")] | ||||
| pub fn verify_json_number(data: &Value, schema: &NumberSchema) -> Result<(), Error> { | ||||
|     if let Some(value) = data.as_f64() { | ||||
|         schema.check_constraints(value) | ||||
|     } else { | ||||
|         bail!("Expected number value."); | ||||
|     } | ||||
|     schema.verify_json(data) | ||||
| } | ||||
| 
 | ||||
| /// Verify JSON value using an `ArraySchema`.
 | ||||
| #[deprecated(note = "use the method array_schema.verify_json() instead")] | ||||
| pub fn verify_json_array(data: &Value, schema: &ArraySchema) -> Result<(), Error> { | ||||
|     let list = match data { | ||||
|         Value::Array(ref list) => list, | ||||
|         Value::Object(_) => bail!("Expected array - got object."), | ||||
|         _ => bail!("Expected array - got scalar value."), | ||||
|     }; | ||||
| 
 | ||||
|     schema.check_length(list.len())?; | ||||
| 
 | ||||
|     for (i, item) in list.iter().enumerate() { | ||||
|         let result = verify_json(item, schema.items); | ||||
|         if let Err(err) = result { | ||||
|             let mut errors = ParameterError::new(); | ||||
|             errors.add_errors(&format!("[{}]", i), err); | ||||
|             return Err(errors.into()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     Ok(()) | ||||
|     schema.verify_json(data) | ||||
| } | ||||
| 
 | ||||
| /// Verify JSON value using an `ObjectSchema`.
 | ||||
| #[deprecated(note = "use the verify_json() method via the ObjectSchemaType trait instead")] | ||||
| pub fn verify_json_object(data: &Value, schema: &dyn ObjectSchemaType) -> Result<(), Error> { | ||||
|     let map = match data { | ||||
|         Value::Object(ref map) => map, | ||||
|         Value::Array(_) => bail!("Expected object - got array."), | ||||
|         _ => bail!("Expected object - got scalar value."), | ||||
|     }; | ||||
| 
 | ||||
|     let mut errors = ParameterError::new(); | ||||
| 
 | ||||
|     let additional_properties = schema.additional_properties(); | ||||
| 
 | ||||
|     for (key, value) in map { | ||||
|         if let Some((_optional, prop_schema)) = schema.lookup(key) { | ||||
|             let result = match prop_schema { | ||||
|                 Schema::Object(object_schema) => verify_json_object(value, object_schema), | ||||
|                 Schema::Array(array_schema) => verify_json_array(value, array_schema), | ||||
|                 _ => verify_json(value, prop_schema), | ||||
|             }; | ||||
|             if let Err(err) = result { | ||||
|                 errors.add_errors(key, err); | ||||
|             }; | ||||
|         } else if !additional_properties { | ||||
|             errors.push( | ||||
|                 key.to_string(), | ||||
|                 format_err!("schema does not allow additional properties."), | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for (name, optional, _prop_schema) in schema.properties() { | ||||
|         if !(*optional) && data[name] == Value::Null { | ||||
|             errors.push( | ||||
|                 name.to_string(), | ||||
|                 format_err!("property is missing and it is not optional."), | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if !errors.is_empty() { | ||||
|         Err(errors.into()) | ||||
|     } else { | ||||
|         Ok(()) | ||||
|     } | ||||
|     schema.verify_json(data) | ||||
| } | ||||
| 
 | ||||
| /// API types should define an "updater type" via this trait in order to support derived "Updater"
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Wolfgang Bumiller
						Wolfgang Bumiller