Documentation
¶
Overview ¶
Package validate provides Validate-step middleware for advanced field rules that cannot be expressed with static mfx struct tags.
Index ¶
- func CrossFieldValidate(fn CrossFieldValidateFunc) maniflex.MiddlewareFunc
- func DateRange(startField, endField string) maniflex.MiddlewareFunc
- func ForbiddenValues(field string, values ...string) maniflex.MiddlewareFunc
- func NumericPrecision(field string, precision, scale int) maniflex.MiddlewareFunc
- func RegexField(field, pattern string) maniflex.MiddlewareFunc
- func RequireAtLeastOne(fields ...string) maniflex.MiddlewareFunc
- func RequireLocale(field string, locales ...string) maniflex.MiddlewareFunc
- func RequireWhen(targetField string, conditions ...string) maniflex.MiddlewareFunc
- func UniqueField(db DBQuerier, driver maniflex.DriverType, field string) maniflex.MiddlewareFunc
- type CrossFieldValidateFunc
- type DBQuerier
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CrossFieldValidate ¶
func CrossFieldValidate(fn CrossFieldValidateFunc) maniflex.MiddlewareFunc
CrossFieldValidate runs an arbitrary function against ctx.ParsedBody and returns 422 if it returns an error. Use this for rules that involve multiple fields (e.g. end_date must be after start_date).
server.Pipeline.Validate.Register(validate.CrossFieldValidate(func(body map[string]any) error {
start, _ := body["start_date"].(string)
end, _ := body["end_date"].(string)
if start != "" && end != "" && end <= start {
return fmt.Errorf("end_date must be after start_date")
}
return nil
}), maniflex.ForModel("Event"))
func DateRange ¶
func DateRange(startField, endField string) maniflex.MiddlewareFunc
DateRange validates that endField is not before startField. Both fields must be RFC3339 timestamps or YYYY-MM-DD date strings. If either field is absent, nil, or unparseable, the rule passes silently — pair with the `required` mfx tag or another rule when presence matters.
server.Pipeline.Validate.Register(
validate.DateRange("start_date", "end_date"),
maniflex.ForModel("Booking"),
maniflex.ForOperation(maniflex.OpCreate, maniflex.OpUpdate),
)
func ForbiddenValues ¶
func ForbiddenValues(field string, values ...string) maniflex.MiddlewareFunc
ForbiddenValues rejects the request with 422 if the named field contains any of the given values. Useful for preventing privilege escalation (e.g. a user setting their own role to "superadmin").
server.Pipeline.Validate.Register(
validate.ForbiddenValues("role", "superadmin", "system"),
maniflex.ForModel("User"),
maniflex.ForOperation(maniflex.OpCreate, maniflex.OpUpdate),
)
func NumericPrecision ¶
func NumericPrecision(field string, precision, scale int) maniflex.MiddlewareFunc
NumericPrecision enforces decimal precision and scale on an incoming numeric field. `precision` is the maximum total number of significant digits; `scale` is the maximum number of digits after the decimal point. Either limit can be disabled by passing 0.
The check is a string-parse of the JSON value, so it is independent of how the column is stored (INTEGER, NUMERIC(p,s), TEXT, DECIMAL). Numbers are normalised by trimming a leading "+"/"-", stripping the decimal point, and removing leading zeros from the integer part before counting digits.
Non-numeric strings, absent fields, and nil values are skipped — pair with the `required` mfx tag or another rule when presence matters.
server.Pipeline.Validate.Register(
validate.NumericPrecision("amount", 19, 4), // up to 19 digits, max 4 after the point
maniflex.ForModel("Invoice"),
)
func RegexField ¶
func RegexField(field, pattern string) maniflex.MiddlewareFunc
RegexField validates that a field's string value matches the given regular expression. Non-string values and absent fields are silently skipped. Returns 422 if the field is present but does not match.
server.Pipeline.Validate.Register(
validate.RegexField("phone", `^\+?[0-9\s\-]{7,15}$`),
maniflex.ForModel("Contact"),
)
func RequireAtLeastOne ¶
func RequireAtLeastOne(fields ...string) maniflex.MiddlewareFunc
RequireAtLeastOne returns 422 if none of the listed fields are present and non-nil in ctx.ParsedBody. Useful for PATCH endpoints where the body must contain at least one meaningful field.
server.Pipeline.Validate.Register(
validate.RequireAtLeastOne("name", "email", "phone"),
maniflex.ForModel("Contact"),
maniflex.ForOperation(maniflex.OpUpdate),
)
func RequireLocale ¶
func RequireLocale(field string, locales ...string) maniflex.MiddlewareFunc
RequireLocale ensures that a maniflex.LocaleString field (mfx:"locale") in the request body contains non-empty values for every required locale key. Returns 422 MISSING_LOCALE with the list of missing keys when any are absent.
server.Pipeline.Validate.Register(
validate.RequireLocale("name", "en", "ar"),
maniflex.ForModel("Department"),
maniflex.ForOperation(maniflex.OpCreate, maniflex.OpUpdate),
)
func RequireWhen ¶
func RequireWhen(targetField string, conditions ...string) maniflex.MiddlewareFunc
RequireWhen makes targetField required when all listed conditions are satisfied. Each condition has the form "field:op:value" where op is one of:
eq — string equality ne — string inequality gt — numeric greater-than gte — numeric greater-than-or-equal lt — numeric less-than lte — numeric less-than-or-equal
Multiple conditions are ANDed: all must hold for the requirement to trigger. If the conditions are met but targetField is absent, nil, or empty string, the request is rejected with 422 VALIDATION_ERROR. Invalid condition syntax panics at registration time (startup), not at request time.
server.Pipeline.Validate.Register(
validate.RequireWhen("rejection_reason", "status:eq:rejected"),
maniflex.ForModel("Claim"),
)
server.Pipeline.Validate.Register(
validate.RequireWhen("shipping_address", "order_type:eq:physical", "region:ne:digital"),
maniflex.ForModel("Order"),
)
func UniqueField ¶
func UniqueField(db DBQuerier, driver maniflex.DriverType, field string) maniflex.MiddlewareFunc
UniqueField runs a SELECT COUNT(*) before the DB step to verify that the given field's value does not already exist in the table. Returns 422 if a duplicate is found, with a user-friendly error message.
`field` is the JSON field name as it appears in ctx.ParsedBody; the actual DB column is resolved through ctx.Model.FieldByJSONName. If the JSON name has no matching field on the model, `field` is used verbatim as a DB column name (preserves backward-compat for callers that already used DB names).
`driver` selects the SQL dialect for placeholders (`$N` for Postgres, `?` for SQLite) and is required because *sql.DB does not expose its driver. Pass the same driver value that was used to open the maniflex DB adapter.
On update operations, the current record's own row is excluded from the check (so saving without changing the unique field does not produce a false positive).
server.Pipeline.Validate.Register(
validate.UniqueField(db, maniflex.Postgres, "email"),
maniflex.ForModel("User"),
)
Types ¶
type CrossFieldValidateFunc ¶
CrossFieldValidateFunc is a user-supplied multi-field validation function. Return a non-nil error to fail validation; the error message is included in the 422 response.