Robust Request Validation in Go
Building APIs often requires validating incoming requests to ensure data integrity and prevent errors. This challenge focuses on creating a reusable request validation system in Go, allowing you to define validation rules and efficiently check incoming data against those rules. This is crucial for building secure and reliable APIs.
Problem Description
You are tasked with creating a Validator struct and associated functions to validate incoming request data. The validator should allow you to define validation rules for different fields within a request. These rules should include checks for required fields, data types, minimum/maximum lengths/values, and regular expression matching. The validator should return a list of error messages if validation fails, and no errors if validation succeeds.
Key Requirements:
- Define Validation Rules: The validator should allow you to define rules for each field in a request. Rules should include:
Required: Whether the field is mandatory.Type: The expected data type (e.g., string, integer, float).MinLength: Minimum length for string fields.MaxLength: Maximum length for string fields.MinValue: Minimum value for numeric fields.MaxValue: Maximum value for numeric fields.Regex: A regular expression to match against string fields.
- Validate Request Data: The validator should take a map representing the request data and a map representing the defined validation rules as input.
- Return Validation Errors: If any validation rule is violated, the validator should return a slice of error messages, each describing the specific validation failure. If all rules pass, it should return an empty slice.
- Reusable Design: The validator should be designed to be reusable across different request types.
Expected Behavior:
The Validate function should iterate through the request data and validation rules, applying the appropriate checks for each field. If a rule is violated, an error message should be added to the error slice. The function should handle cases where a field exists in the rules but not in the request data (and is required).
Edge Cases to Consider:
- Empty request data.
- Missing required fields.
- Incorrect data types.
- Values outside the specified range (min/max).
- Invalid regular expressions.
- Fields present in the request but not defined in the validation rules.
Examples
Example 1:
Input:
Request Data: map[name:John Doe age:30 email:john.doe@example.com]
Validation Rules: map[name:map[Required:true Type:string MinLength:2 MaxLength:50 Email:true] age:map[Required:true Type:integer MinValue:18 MaxValue:120] email:map[Required:true Type:string Regex:"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"]]
Output: []error
Explanation: All validation rules pass.
Example 2:
Input:
Request Data: map[name:John age:abc email:john.doe@example.com]
Validation Rules: map[name:map[Required:true Type:string MinLength:2 MaxLength:50] age:map[Required:true Type:integer MinValue:18 MaxValue:120] email:map[Required:true Type:string Regex:"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"]]
Output: [error:age must be an integer]
Explanation: The 'age' field has an incorrect data type (string instead of integer).
Example 3:
Input:
Request Data: map[name:John Doe]
Validation Rules: map[name:map[Required:true Type:string MinLength:2 MaxLength:50] age:map[Required:true Type:integer MinValue:18 MaxValue:120] email:map[Required:true Type:string Regex:"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"]]
Output: [error:age is required]
Explanation: The 'age' field is required but missing from the request data.
Constraints
- The request data and validation rules will be represented as
map[string]interface{}. You'll need to handle type assertions appropriately. - The regular expression matching should use the
regexppackage in Go. - The validator should be efficient enough to handle requests with a reasonable number of fields (up to 50).
- Error messages should be clear and informative, indicating the field name and the reason for the validation failure.
Notes
- Consider using a helper function to perform type checking.
- Think about how to handle different data types (string, integer, float) in your validation rules.
- The
Email:truerule in the example is a placeholder. You should implement the actual email regex validation. - Focus on creating a flexible and extensible validator that can be easily adapted to different request types. Consider how you might add new validation rules in the future.
- Error handling is important. Gracefully handle invalid regular expressions or unexpected data types.