module util.validation.common; import handy_http_primitives.optional; import std.datetime; struct ValidationError { string field; string message; } interface ValidationRule(T) { Optional!ValidationError validate(in T payload); } ValidationError[] applyValidationRules(T)(ValidationRule!(T)[] rules, in T payload) { import std.array; auto app = appender!(ValidationError[]); foreach (rule; rules) { auto result = rule.validate(payload); if (result) app ~= result.value; } return app[]; } // Helper functions: void validateTags(in string[] tags) { import std.regex; import handy_http_primitives: HttpStatus, HttpStatusException; foreach (tag; tags) { import std.regex; auto r = ctRegex!(`^[a-z0-9-_]{3,32}$`); if (!matchFirst(tag, r)) { throw new HttpStatusException(HttpStatus.BAD_REQUEST, "Invalid tag: \"" ~ tag ~ "\"."); } } } SysTime validateTimestampFormat(string timestampStr) { import handy_http_primitives: HttpStatus, HttpStatusException; try { return SysTime.fromISOExtString(timestampStr, UTC()); } catch (TimeException e) { throw new HttpStatusException(HttpStatus.BAD_REQUEST, "Invalid timestamp format. Expected ISO-8601 datetime."); } }