├── .github └── workflows │ └── go.yml ├── LICENSE ├── README.md ├── go.mod ├── rules.go └── zogo.go /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a golang project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go 3 | 4 | name: Go 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | jobs: 13 | 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | 19 | - name: Set up Go 20 | uses: actions/setup-go@v4 21 | with: 22 | go-version: '1.20' 23 | 24 | - name: Build 25 | run: go build -v ./... 26 | 27 | - name: Test 28 | run: go test -v ./... 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Francisco Inoque 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zogo - Custom Validation Library for Go 2 | 3 | Zogo is a custom validation library for Go that allows you to define and apply various validation rules to your data. It is inspired by Zod's zogo. 4 | 5 | ## Features 6 | 7 | - Define custom validation rules for different types of data. 8 | - Easily validate fields using predefined or custom validation functions. 9 | - Intuitive and flexible way to validate complex data structures. 10 | 11 | ## Installation 12 | 13 | To use Zogo in your Go project, you can install it using the `go get` command: 14 | 15 | ```sh 16 | go get github.com/frantchessico/zogo 17 | 18 | ``` 19 | ## Usage 20 | Here's an example of how you can use Zogo to define and validate data: 21 | 22 | 23 | ```go 24 | 25 | package main 26 | 27 | import ( 28 | "fmt" 29 | "github.com/frantchessico/zogo" 30 | ) 31 | 32 | func main() { 33 | validator := zogo.NewRuleValidator() 34 | 35 | validator.AddRule("age", zogo.MinValueValidator(18)) 36 | validator.AddRule("name", zogo.StringNotEmptyValidator) 37 | validator.AddRule("email", zogo.EmailSchema) 38 | validator.AddRule("password", zogo.MinValueValidator(4)) 39 | 40 | data := map[string]interface{}{ 41 | "age": 25, 42 | "name": "John Doe", 43 | "email": "john@example.com", 44 | "password": "secretpw", 45 | } 46 | 47 | err := validator.Validate(data) 48 | if err != nil { 49 | fmt.Println("Validation failed:", err) 50 | } else { 51 | fmt.Println("Validation successful!") 52 | } 53 | } 54 | ``` 55 | 56 | ## Available Validation Rules 57 | 58 | Zogo provides the following validation rules that you can use to validate your data fields: 59 | 60 | - `zogo.MinValueValidator(minValue int)`: Validates that a numeric value is greater than or equal to the specified minimum value. 61 | - `zogo.MinLengthValidator(minLength int)`: Validates that a string value has a minimum length. 62 | - `zogo.StringNotEmptyValidator(value interface{})`: Validates that a string value is not empty. 63 | - `zogo.MaxLengthValidator(maxLength int)`: Validates that a string value has a maximum length. 64 | - `zogo.MaxValueValidator(maxValue float64)`: Validates that a numeric value is less than or equal to the specified maximum value. 65 | - `zogo.EmailSchema(value interface{})`: Validates that a string value is a valid email address. 66 | - `zogo.BooleanSchema(value interface{})`: Validates boolean values (true or false). 67 | - `zogo.StringSchema(value interface{})`: Validates string values. 68 | - `zogo.NumberSchema(value interface{})`: Validates numeric values. 69 | 70 | 71 | ## Author 72 | 73 | This library is authored by Francisco Inoque. 74 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/frantchessico/zogo 2 | 3 | go 1.19 4 | -------------------------------------------------------------------------------- /rules.go: -------------------------------------------------------------------------------- 1 | package zogo 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "regexp" 7 | ) 8 | 9 | 10 | func MinLengthValidator(minLength int) FieldValidator { 11 | return func(value interface{}) error { 12 | strValue, ok := value.(string) 13 | if !ok { 14 | return errors.New("must be a string") 15 | } 16 | if len(strValue) < minLength { 17 | return fmt.Errorf("must have a minimum length of %d", minLength) 18 | } 19 | return nil 20 | } 21 | } 22 | 23 | func MinValueValidator(minValue int) FieldValidator { 24 | return func(value interface{}) error { 25 | num, ok := value.(int) 26 | if !ok { 27 | return errors.New("must be an integer") 28 | } 29 | if num < minValue { 30 | return fmt.Errorf("must be greater than or equal to %d", minValue) 31 | } 32 | return nil 33 | } 34 | } 35 | 36 | func MaxLengthValidator(maxLength int) FieldValidator { 37 | return func(value interface{}) error { 38 | strValue, ok := value.(string) 39 | if !ok { 40 | return errors.New("must be a string") 41 | } 42 | if len(strValue) > maxLength { 43 | return fmt.Errorf("must have a maximum length of %d", maxLength) 44 | } 45 | return nil 46 | } 47 | } 48 | 49 | func MaxValueValidator(maxValue float64) FieldValidator { 50 | return func(value interface{}) error { 51 | num, ok := value.(float64) 52 | if !ok { 53 | return errors.New("must be a number") 54 | } 55 | if num > maxValue { 56 | return fmt.Errorf("must be less than or equal to %f", maxValue) 57 | } 58 | return nil 59 | } 60 | } 61 | 62 | func StringNotEmptyValidator(value interface{}) error { 63 | str, ok := value.(string) 64 | if !ok { 65 | return errors.New("must be a string") 66 | } 67 | if str == "" { 68 | return errors.New("cannot be empty") 69 | } 70 | return nil 71 | } 72 | 73 | 74 | 75 | // EmailRegexValidator is a field validation function for email using RegEx. 76 | var EmailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`) 77 | 78 | func EmailSchema(value interface{}) error { 79 | if value == nil || value == "" { 80 | return nil 81 | } 82 | 83 | email, ok := value.(string) 84 | if !ok { 85 | return fmt.Errorf("must be a string or nil") 86 | } 87 | 88 | if !EmailRegex.MatchString(email) { 89 | return fmt.Errorf("invalid email format") 90 | } 91 | 92 | return nil 93 | } 94 | 95 | 96 | func BooleanSchema(value interface{}) error { 97 | if value == nil { 98 | return nil // Field is undefined or null 99 | } 100 | 101 | _, ok := value.(bool) 102 | if !ok { 103 | return fmt.Errorf("must be a boolean or nil") 104 | } 105 | 106 | return nil 107 | } 108 | 109 | 110 | // StringSchema is a field validation function for string values. 111 | func StringSchema(value interface{}) error { 112 | if value == nil { 113 | return nil // Field is undefined or null 114 | } 115 | 116 | _, ok := value.(string) 117 | if !ok { 118 | return fmt.Errorf("must be a string or nil") 119 | } 120 | 121 | return nil 122 | } 123 | 124 | 125 | func NumberSchema(value interface{}) error { 126 | if value == nil { 127 | return nil // Field is undefined or null 128 | } 129 | 130 | _, ok := value.(float64) 131 | if !ok { 132 | return fmt.Errorf("must be a number or nil") 133 | } 134 | 135 | return nil 136 | } 137 | -------------------------------------------------------------------------------- /zogo.go: -------------------------------------------------------------------------------- 1 | package zogo 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // FieldValidator defines the signature of a field validation function. 8 | type FieldValidator func(value interface{}) error 9 | 10 | // RuleValidator is a struct to manage validation rules for fields. 11 | type RuleValidator struct { 12 | Rules map[string][]FieldValidator 13 | } 14 | 15 | // NewRuleValidator creates a new instance of RuleValidator. 16 | func NewRuleValidator() *RuleValidator { 17 | return &RuleValidator{ 18 | Rules: make(map[string][]FieldValidator), 19 | } 20 | } 21 | 22 | // AddRule adds a validation rule for a specific field. 23 | func (v *RuleValidator) AddRule(field string, validators ...FieldValidator) { 24 | v.Rules[field] = append(v.Rules[field], validators...) 25 | } 26 | 27 | // Validate validates the provided data against the defined rules. 28 | func (v *RuleValidator) Validate(data map[string]interface{}) error { 29 | for field, rules := range v.Rules { 30 | value, exists := data[field] 31 | if !exists { 32 | return fmt.Errorf("field '%s' not found", field) 33 | } 34 | 35 | for _, rule := range rules { 36 | if err := rule(value); err != nil { 37 | return fmt.Errorf("field '%s': %v", field, err) 38 | } 39 | } 40 | } 41 | 42 | return nil 43 | } 44 | --------------------------------------------------------------------------------