/// Define extension Validator where T == String { /// Validates whether a `String` is a valid email address. public static var zipCode: Validator { .init { guard let range = $0.range(of: zipCodeRegex, options: [.regularExpression]), range.lowerBound == $0.startIndex && range.upperBound == $0.endIndex else { return ValidatorResults.ZipCode(isValidZipCode: false) } return ValidatorResults.ZipCode(isValidZipCode: true) } } /// Validates whether a `String` is a valid two letter state. public static var usState: Validator { .init { guard validStates.contains($0) else { return ValidatorResults.USState(isValidState: false) } return ValidatorResults.USState(isValidState: true) } } } extension ValidatorResults { /// `ValidatorResult` of a validator that validates whether a `String` is a valid zip code. public struct ZipCode { /// The input is a valid zip code public let isValidZipCode: Bool } /// `ValidatorResult` of a validator that validates whether a `String` is a valid two letter state. public struct USState { /// The input is a valid state public let isValidState: Bool } } extension ValidatorResults.ZipCode: ValidatorResult { public var isFailure: Bool { !self.isValidZipCode } public var successDescription: String? { "is a valid zip code" } public var failureDescription: String? { "is not a valid zip code" } } extension ValidatorResults.USState: ValidatorResult { public var isFailure: Bool { !self.isValidState } public var successDescription: String? { "is a valid state" } public var failureDescription: String? { "is not a valid state" } } private let zipCodeRegex: String = "^\\d{5}(?:[-\\s]\\d{4})?$" private let validStates = [ "AK", "AL", "AR", "AZ", "CA", "CO", "CT", "DC", "DE", "FL", "GA", "HI", "IA", "ID", "IL", "IN", "KS", "KY", "LA", "MA", "MD", "ME", "MI", "MN", "MO", "MS", "MT", "NE", "NC", "ND", "NH", "NJ", "NM", "NY", "NV", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VA", "VT", "WA", "WI", "WV", "WY", "AS", "GU", "MH", "PR", "UM", ] /// Usage extension CreateUserData: Validatable { public static func validations(_ validations: inout Validations) { // ... validations.add("addressZipCode", as: String.self, is: .zipCode, required: false) validations.add("addressState", as: String.self, is: .usState, required: false) } }