Skip to content

A powerful Zod-like schema validation library for Go, built to validate everything from primitive data types to custom structs. Technically inspired by the excellent `zod` TypeScript library, and philosophically inspired by Indonesia’s useless Minister of Energy and Mineral Resources.

License

Notifications You must be signed in to change notification settings

ivanj26/bahlidator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Bahlidator - a Zod-like validator for Go

Tests Code Style Latest Version License

Bahlidator

A powerful validator philosophically inspired by Bahlil Lahadalia

Bahlidator is a Zod-like typescript schema-based validation library designed for Go that validates any kind of value: primitive types, complex structures, arrays, enums, dates, and deeply nested combinations of all of them.

It was built with the concepts below:

  • Technically inspired by the excellent zod TypeScript library.
  • Philosophically inspired by Bahlil Lahadalia, Indonesia’s useless Minister of Energy and Mineral Resources.

🧠 Why “Bahlidator”?

Because sometimes software exists to remind us that:

If an incompetent figure like Bahlil can pass validation in real life, your data should at least be held to a higher standard.


✨ Features

  • 🔤 Rich Primitives: Fluent validation for string, number, and boolean types with checks like Min, Max, Regex, Positive, etc.
  • 🧩 Complex Structures: Validate map[string]any or custom structs against a shape of schemas, with support for json and b tags.
  • 🌳 Deeply Nested Validation: Recursively validate nested objects and arrays.
  • 📦 Arrays: Check array Min, Max, Length, and whether it Contains a specific element. Validates each element against a given schema.
  • 📋 Enums: Ensure a value is one of a predefined set of values.
  • 📅 Dates: Validate time.Time or date-strings (RFC3339) with Min, Max, and Between.
  • 🧠 Fluent API: Chainable, Zod-like methods for building complex schemas declaratively.
  • 🧪 Path-Aware Errors: Get a full list of validation errors with paths (e.g., user.profile.age, items[2].name) to easily locate issues.
  • 🎨 Customizable Messages: Override default error messages for any rule.

📦 Installation

go get github.com/ivanj26/bahlidator

🚀 Quick Examples

🔤 String Validation

import "github.com/ivanj26/bahlidator/b"

schema := b.String().
    Min(1).
    Max(255).
    Required()

isValid, err := schema.Validate("hello world") // true, nil

🔢 Numeric Validation

import "github.com/ivanj26/bahlidator/b"

// Numeric schema uses a generic type of numeric (unsigned integers, signed integers, and floating number)

// You can define the specific numeric type in your schema
schemaInt := b.Numeric[int]().
    Min(1).
    Max(10)

isValid, errs := schemaInt.Validate(1) // true, nil


// As float64
schemaFloat64 := b.Numeric[float64]().
    Min(1.0).
    Max(10.0)

isValid, errs := schemaFloat64.Validate(1.0) // true, nil

📋 Enum Validation

import "github.com/ivanj26/bahlidator/b"

type Role int

const (
	SuperAdmin Role = 0
	Admin      Role = 1
	User       Role = 2
)

schema := b.Enum([]Role{Admin, User, SuperAdmin}).Required()
isValid, err := schema.Validate(Admin) // true, nil

📅 Date Validation

import (
	"time"
	"github.com/ivanj26/bahlidator/b"
)

schema := b.Date[time.Time]().
    Min(time.Now()).
    Required()

isValid, err := schema.Validate(time.Now()) // true, nil

📦 Array Validation

import "github.com/ivanj26/bahlidator/b"

schema := b.Array(
        b.String().Min(1),
    ).Min(1)

isValid, err := schema.Validate([]string{"hello", "world"}) // true, nil

🧩 Object Validation

import (
	"fmt"
	"github.com/ivanj26/bahlidator/b"
	"github.com/ivanj26/bahlidator/b/schemas"
)

schema := b.Object(map[string]schemas.BaseSchema{
    "user": b.Object(map[string]schemas.BaseSchema{
        "email":    b.String().Required(),
        "fullName": b.String().Min(3),
    }),
    "items": b.Array(
        b.Object(map[string]schemas.BaseSchema{
            "name": b.String().Required(),
        }),
    ).Min(1),
})

// Call .Validate() to validate against the input
// `obj` can be a map[string]any or your own struct with "json" or "b" tags
obj := map[string]any{
	"user": map[string]any{
		"email":    "test@example.com",
		"fullName": "Bahlil",
	},
	"items": []map[string]any{
		{"name": "Laptop"},
	},
}
isValid, errs := schema.Validate(obj)

if !isValid {
    for _, e := range errs.Errors {
        fmt.Printf("Field: %s, Error: %s\n", *e.Path, e.Message)
    }
}

🧪 Validation Philosophy

Bahlidator validates data the way reality validates authority:

  • It validates everything, not just objects
  • It is strict where it matters and explicit when it fails
  • Confidence alone is not enough — unlike certain real-world systems
  • All errors are returned, none are silently ignored

🚨 Error Handling

Errors are aggregated and path-aware:

user.email: string is required and cannot be empty
user.fullName: string length is less than the minimum allowed
items[0].name: string is required and cannot be empty

No panics. No guesswork. (Unlike policy decisions.)


🎨 Custom Error Messages

You can override the default error message for any validation rule by passing opts.WithCustomMessage("your message") as the last argument.

import "github.com/ivanj26/bahlidator/b"
import "github.com/ivanj26/bahlidator/b/opts"

schema := b.
    String().
    Min(
        5,
        opts.WithCustomMessage("Input string is too short, must be at least 5 characters."),
    )

isValid, errs := schema.Validate("oops")

if !isValid {
    // errs.Errors[0].Message will be "Input string is too short, must be at least 5 characters."
}

🤝 Contributing

Contributions are welcome.

Please:

  • document schema behavior changes
  • avoid unnecessary reflection
  • preserve backward compatibility where possible
  • do not introduce panics or magical behavior

See PULL_REQUEST_TEMPLATE.md.


📄 License

MIT License

About

A powerful Zod-like schema validation library for Go, built to validate everything from primitive data types to custom structs. Technically inspired by the excellent `zod` TypeScript library, and philosophically inspired by Indonesia’s useless Minister of Energy and Mineral Resources.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages