@@ -157,16 +157,38 @@ func validateParamSpec(paramName string, spec ParamSpec) error {
157157func ValidateInputs (inputs map [string ]interface {}, specs map [string ]ParamSpec ) error {
158158 var errors []ParameterError
159159
160- // 1. Apply default values for optional parameters
160+ // 1. Apply default values
161+ applyDefaultValues (inputs , specs )
162+
163+ // 2. Check required parameters
164+ errors = append (errors , checkRequiredParameters (inputs , specs )... )
165+
166+ // 3. Validate parameter types and constraints
167+ errors = append (errors , validateAllParameters (inputs , specs )... )
168+
169+ if len (errors ) > 0 {
170+ return & InputValidationError {
171+ Errors : errors ,
172+ }
173+ }
174+
175+ return nil
176+ }
177+
178+ // applyDefaultValues applies default values for optional parameters.
179+ func applyDefaultValues (inputs map [string ]interface {}, specs map [string ]ParamSpec ) {
161180 for paramName , spec := range specs {
162181 if ! spec .Required && spec .Default != nil {
163182 if _ , exists := inputs [paramName ]; ! exists {
164183 inputs [paramName ] = spec .Default
165184 }
166185 }
167186 }
187+ }
168188
169- // 2. Check required parameters
189+ // checkRequiredParameters validates that all required parameters are present.
190+ func checkRequiredParameters (inputs map [string ]interface {}, specs map [string ]ParamSpec ) []ParameterError {
191+ var errors []ParameterError
170192 for paramName , spec := range specs {
171193 if spec .Required {
172194 if _ , exists := inputs [paramName ]; ! exists {
@@ -180,8 +202,12 @@ func ValidateInputs(inputs map[string]interface{}, specs map[string]ParamSpec) e
180202 }
181203 }
182204 }
205+ return errors
206+ }
183207
184- // 3. Validate parameter types and constraints
208+ // validateAllParameters validates types and constraints for all parameters.
209+ func validateAllParameters (inputs map [string ]interface {}, specs map [string ]ParamSpec ) []ParameterError {
210+ var errors []ParameterError
185211 for paramName , value := range inputs {
186212 spec , exists := specs [paramName ]
187213 if ! exists {
@@ -195,131 +221,161 @@ func ValidateInputs(inputs map[string]interface{}, specs map[string]ParamSpec) e
195221 continue // Skip constraint validation if type is wrong
196222 }
197223
198- // Pattern validation (only for string type)
199- if spec .Pattern != "" && spec .Type == "string" {
200- if err := validatePattern (paramName , value .(string ), spec .Pattern ); err != nil {
201- errors = append (errors , * err )
202- }
203- }
224+ // Constraint validations
225+ errors = append (errors , validateConstraints (paramName , value , spec )... )
226+ }
227+ return errors
228+ }
204229
205- // Enum validation
206- if len (spec .Enum ) > 0 {
207- if err := validateEnumConstraint (paramName , value , spec .Enum ); err != nil {
208- errors = append (errors , * err )
209- }
230+ // validateConstraints validates pattern, enum, and range constraints.
231+ func validateConstraints (paramName string , value interface {}, spec ParamSpec ) []ParameterError {
232+ var errors []ParameterError
233+
234+ // Pattern validation (only for string type)
235+ if spec .Pattern != "" && spec .Type == "string" {
236+ if err := validatePattern (paramName , value .(string ), spec .Pattern ); err != nil {
237+ errors = append (errors , * err )
210238 }
239+ }
211240
212- // Numeric range validation
213- if (spec .Type == "int" || spec .Type == "float" ) && (spec .MinValue != nil || spec .MaxValue != nil ) {
214- if err := validateRange (paramName , value , spec .MinValue , spec .MaxValue ); err != nil {
215- errors = append (errors , * err )
216- }
241+ // Enum validation
242+ if len (spec .Enum ) > 0 {
243+ if err := validateEnumConstraint (paramName , value , spec .Enum ); err != nil {
244+ errors = append (errors , * err )
217245 }
218246 }
219247
220- if len (errors ) > 0 {
221- return & InputValidationError {
222- Errors : errors ,
248+ // Numeric range validation
249+ if (spec .Type == "int" || spec .Type == "float" ) && (spec .MinValue != nil || spec .MaxValue != nil ) {
250+ if err := validateRange (paramName , value , spec .MinValue , spec .MaxValue ); err != nil {
251+ errors = append (errors , * err )
223252 }
224253 }
225254
226- return nil
255+ return errors
227256}
228257
229258// validateType validates parameter type matches expected type.
230259// Handles JSON number compatibility (all numbers parsed as float64).
231260func validateType (paramName string , value interface {}, expectedType string ) * ParameterError {
232- actualType := getGoType (value )
233-
234261 switch expectedType {
235262 case "string" :
236- if _ , ok := value .(string ); ! ok {
237- return & ParameterError {
238- ParamName : paramName ,
239- ErrorType : "TypeMismatch" ,
240- Expected : "string" ,
241- Actual : actualType ,
242- Message : fmt .Sprintf ("expected string, got %s" , actualType ),
243- }
244- }
245-
263+ return validateStringType (paramName , value )
246264 case "int" :
247- switch v := value .(type ) {
248- case int , int32 , int64 :
249- return nil // Native int types
250- case float64 :
251- // JSON-parsed numbers, check if it's a whole number
252- if v == float64 (int64 (v )) {
253- return nil // ✅ 30.0 is valid int
254- }
255- // Reject floats with decimal parts
256- return & ParameterError {
257- ParamName : paramName ,
258- ErrorType : "TypeMismatch" ,
259- Expected : "int (whole number)" ,
260- Actual : fmt .Sprintf ("float64(%v)" , v ),
261- Message : fmt .Sprintf ("expected integer, got float with decimal: %v" , v ),
262- }
263- default :
264- return & ParameterError {
265- ParamName : paramName ,
266- ErrorType : "TypeMismatch" ,
267- Expected : "int" ,
268- Actual : actualType ,
269- Message : fmt .Sprintf ("expected int, got %s" , actualType ),
270- }
265+ return validateIntType (paramName , value )
266+ case "float" :
267+ return validateFloatType (paramName , value )
268+ case "bool" :
269+ return validateBoolType (paramName , value )
270+ case "object" :
271+ return validateObjectType (paramName , value )
272+ case "array" :
273+ return validateArrayType (paramName , value )
274+ default :
275+ return nil
276+ }
277+ }
278+
279+ // validateStringType validates string type.
280+ func validateStringType (paramName string , value interface {}) * ParameterError {
281+ if _ , ok := value .(string ); ! ok {
282+ return & ParameterError {
283+ ParamName : paramName ,
284+ ErrorType : "TypeMismatch" ,
285+ Expected : "string" ,
286+ Actual : getGoType (value ),
287+ Message : fmt .Sprintf ("expected string, got %s" , getGoType (value )),
271288 }
289+ }
290+ return nil
291+ }
272292
273- case "float" :
274- switch value .(type ) {
275- case float32 , float64 :
276- return nil
277- case int , int32 , int64 :
278- return nil // ✅ int can be implicitly converted to float
279- default :
280- return & ParameterError {
281- ParamName : paramName ,
282- ErrorType : "TypeMismatch" ,
283- Expected : "float" ,
284- Actual : actualType ,
285- Message : fmt .Sprintf ("expected float, got %s" , actualType ),
286- }
293+ // validateIntType validates integer type with JSON compatibility.
294+ func validateIntType (paramName string , value interface {}) * ParameterError {
295+ switch v := value .(type ) {
296+ case int , int32 , int64 :
297+ return nil // Native int types
298+ case float64 :
299+ // JSON-parsed numbers, check if it's a whole number
300+ if v == float64 (int64 (v )) {
301+ return nil // ✅ 30.0 is valid int
287302 }
303+ // Reject floats with decimal parts
304+ return & ParameterError {
305+ ParamName : paramName ,
306+ ErrorType : "TypeMismatch" ,
307+ Expected : "int (whole number)" ,
308+ Actual : fmt .Sprintf ("float64(%v)" , v ),
309+ Message : fmt .Sprintf ("expected integer, got float with decimal: %v" , v ),
310+ }
311+ default :
312+ return & ParameterError {
313+ ParamName : paramName ,
314+ ErrorType : "TypeMismatch" ,
315+ Expected : "int" ,
316+ Actual : getGoType (value ),
317+ Message : fmt .Sprintf ("expected int, got %s" , getGoType (value )),
318+ }
319+ }
320+ }
288321
289- case "bool" :
290- if _ , ok := value .(bool ); ! ok {
291- return & ParameterError {
292- ParamName : paramName ,
293- ErrorType : "TypeMismatch" ,
294- Expected : "bool" ,
295- Actual : actualType ,
296- Message : fmt .Sprintf ("expected bool, got %s" , actualType ),
297- }
322+ // validateFloatType validates float type.
323+ func validateFloatType (paramName string , value interface {}) * ParameterError {
324+ switch value .(type ) {
325+ case float32 , float64 :
326+ return nil
327+ case int , int32 , int64 :
328+ return nil // ✅ int can be implicitly converted to float
329+ default :
330+ return & ParameterError {
331+ ParamName : paramName ,
332+ ErrorType : "TypeMismatch" ,
333+ Expected : "float" ,
334+ Actual : getGoType (value ),
335+ Message : fmt .Sprintf ("expected float, got %s" , getGoType (value )),
298336 }
337+ }
338+ }
299339
300- case "object" :
301- if _ , ok := value .( map [ string ] interface {}); ! ok {
302- return & ParameterError {
303- ParamName : paramName ,
304- ErrorType : "TypeMismatch" ,
305- Expected : "object (map[string]interface{}) " ,
306- Actual : actualType ,
307- Message : fmt . Sprintf ( "expected object, got %s" , actualType ),
308- }
340+ // validateBoolType validates boolean type.
341+ func validateBoolType ( paramName string , value interface {}) * ParameterError {
342+ if _ , ok := value .( bool ); ! ok {
343+ return & ParameterError {
344+ ParamName : paramName ,
345+ ErrorType : "TypeMismatch " ,
346+ Expected : "bool" ,
347+ Actual : getGoType ( value ),
348+ Message : fmt . Sprintf ( "expected bool, got %s" , getGoType ( value )),
309349 }
350+ }
351+ return nil
352+ }
310353
311- case "array" :
312- if _ , ok := value .([] interface {}); ! ok {
313- return & ParameterError {
314- ParamName : paramName ,
315- ErrorType : "TypeMismatch" ,
316- Expected : "array ([]interface{}) " ,
317- Actual : actualType ,
318- Message : fmt . Sprintf ( "expected array, got %s" , actualType ),
319- }
354+ // validateObjectType validates object (map) type.
355+ func validateObjectType ( paramName string , value interface {}) * ParameterError {
356+ if _ , ok := value .( map [ string ] interface {}); ! ok {
357+ return & ParameterError {
358+ ParamName : paramName ,
359+ ErrorType : "TypeMismatch " ,
360+ Expected : "object (map[string]interface{})" ,
361+ Actual : getGoType ( value ),
362+ Message : fmt . Sprintf ( "expected object, got %s" , getGoType ( value )),
320363 }
321364 }
365+ return nil
366+ }
322367
368+ // validateArrayType validates array (slice) type.
369+ func validateArrayType (paramName string , value interface {}) * ParameterError {
370+ if _ , ok := value .([]interface {}); ! ok {
371+ return & ParameterError {
372+ ParamName : paramName ,
373+ ErrorType : "TypeMismatch" ,
374+ Expected : "array ([]interface{})" ,
375+ Actual : getGoType (value ),
376+ Message : fmt .Sprintf ("expected array, got %s" , getGoType (value )),
377+ }
378+ }
323379 return nil
324380}
325381
0 commit comments