Skip to content

Validation

Declarative input validation framework with chainable rules and comprehensive error reporting. Supports common validation patterns for strings, numbers, emails, and URLs.

Import

zig
const api = @import("api");
const Validator = api.Validator;
const validation = api.validation;

Validation Functions Summary

FunctionDescription
isEmail(str)Validate email format
isUrl(str)Validate URL format
isNotEmpty(str)Check non-empty string
isLengthBetween(str, min, max)Validate string length
isNumeric(str)Check numeric string
isAlpha(str)Check alphabetic string
isAlphanumeric(str)Check alphanumeric string
matchesPattern(str, pattern)Match regex pattern

Validator Builder Rules

MethodDescription
.required(field)Field must be present
.minLength(field, len)Minimum string length
.maxLength(field, len)Maximum string length
.email(field)Must be valid email
.url(field)Must be valid URL
.minValue(field, val)Minimum numeric value
.maxValue(field, val)Maximum numeric value
.pattern(field, regex)Must match pattern

Validator Functions

isEmail

zig
pub fn isEmail(email_str: []const u8) bool

Validates email format.

zig
validation.isEmail("user@example.com")  // true
validation.isEmail("invalid")           // false

isUrl

zig
pub fn isUrl(url_str: []const u8) bool

Validates URL format.

zig
validation.isUrl("https://example.com")  // true
validation.isUrl("ftp://example.com")    // false (http/https only)

isNotEmpty

zig
pub fn isNotEmpty(str: []const u8) bool

Checks if string is not empty/whitespace.

zig
validation.isNotEmpty("hello")  // true
validation.isNotEmpty("")       // false
validation.isNotEmpty("   ")    // false

isLengthBetween

zig
pub fn isLengthBetween(str: []const u8, min: usize, max: usize) bool

Validates string length.

zig
validation.isLengthBetween("hello", 1, 10)  // true
validation.isLengthBetween("hi", 5, 10)     // false

Validator Builder

Creating a Validator

zig
const UserValidator = Validator(User);

var validator = UserValidator.init(allocator);
defer validator.deinit();

Chaining Rules

zig
_ = validator
    .required("name")
    .minLength("name", 2)
    .maxLength("name", 100)
    .email("email")
    .minValue("age", 18)
    .maxValue("age", 120);

Validating

zig
const result = validator.validate(user_input);

if (!result.valid) {
    for (result.errors) |err| {
        std.debug.print("{s}: {s}\n", .{err.field, err.message});
    }
}

ValidationError

zig
pub const ValidationError = struct {
    field: []const u8,
    message: []const u8,
    code: ErrorCode,
};

pub const ErrorCode = enum {
    required,
    min_length,
    max_length,
    min_value,
    max_value,
    pattern,
    email,
    url,
    custom,
};

isUuid

zig
pub fn isUuid(uuid_str: []const u8) bool

Validates UUID v4 format.

zig
validation.isUuid("123e4567-e89b-12d3-a456-426614174000")  // true
validation.isUuid("invalid-uuid")                          // false

uuid Rule

Add UUID validation to the Validator builder.

zig
_ = validator.uuid("user_id");

Handler Example

zig
fn createUser(ctx: *api.Context) api.Response {
    const body = ctx.body();

    if (body.len == 0) {
        return api.Response.err(.bad_request, "{\"error\":\"Body required\"}");
    }

    // Parse body
    const User = struct { email: []const u8 };
    const user = api.json.parse(User, ctx.allocator, body) catch {
        return api.Response.err(.bad_request, "{\"error\":\"Invalid JSON\"}");
    };

    // Validate
    if (!api.validation.isEmail(user.email)) {
        return api.Response.err(.bad_request, "{\"error\":\"Invalid email\"}");
    }

    return api.Response.jsonRaw("{\"created\":true}")
        .setStatus(.created);
}

Released under the MIT License.