{"action":"closed","issue":{"url":"https://api.github.com/repos/formbound/Paramount/issues/1","labels_url":"https://api.github.com/repos/formbound/Paramount/issues/1/labels{/name}","comments_url":"https://api.github.com/repos/formbound/Paramount/issues/1/comments","events_url":"https://api.github.com/repos/formbound/Paramount/issues/1/events","html_url":"https://github.com/formbound/Paramount/issues/1","id":118957300,"number":1,"title":"Builder pattern","user":{"login":"paulofaria","id":5126193,"avatar_url":"https://avatars.githubusercontent.com/u/5126193?v=3","gravatar_id":"","url":"https://api.github.com/users/paulofaria","html_url":"https://github.com/paulofaria","followers_url":"https://api.github.com/users/paulofaria/followers","following_url":"https://api.github.com/users/paulofaria/following{/other_user}","gists_url":"https://api.github.com/users/paulofaria/gists{/gist_id}","starred_url":"https://api.github.com/users/paulofaria/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paulofaria/subscriptions","organizations_url":"https://api.github.com/users/paulofaria/orgs","repos_url":"https://api.github.com/users/paulofaria/repos","events_url":"https://api.github.com/users/paulofaria/events{/privacy}","received_events_url":"https://api.github.com/users/paulofaria/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2015-11-26T02:05:10Z","updated_at":"2015-12-05T11:51:22Z","closed_at":"2015-12-05T11:51:22Z","body":"This looks very good. How about using the builder pattern to create the validation rules and them just apply the value to the validator once?\r\n\r\nI used this pattern with [Spell](https://github.com/Zewo/Spell) to create the routes.\r\nThe idea is something like this:\r\n\r\n```swift\r\nprotocol ValidationRule {\r\n}\r\n\r\nstruct IntegerValidationRule: ValidationRule {\r\n}\r\n\r\nstruct StringValidationRule: ValidationRule {\r\n}\r\n\r\nstruct ValidType {\r\n    // Maybe this struct can wrap the original type\r\n    // and based on the validation rules\r\n    // and that the value is valid\r\n    // it can provide type-safe accessors to the underlying value\r\n}\r\n\r\nstruct Validator {\r\n    public final class ValidatorBuilder {\r\n        var rules: [ValidationRule] = []\r\n        public func integer(key: String, minValue: Int = Int.min, maxValue: Int = Int.max) {\r\n            // create a rule based on the arguments\r\n            rules.append(IntegerValidationRule())\r\n        }\r\n\r\n        public func string(key: String, minLength: Int = 0, maxLength: Int = Int.max) {\r\n            // create a rule based on the arguments\r\n            rules.append(StringValidationRule())\r\n        }\r\n\r\n        public func type<T>(key: String, type: T.Type) {\r\n            // maybe support validation that a value must be of type T?\r\n            // maybe create a protocol that lets people create custom validation rules\r\n            // for custom types?\r\n            rules.append(CustomTypeValidationRule())\r\n        }\r\n\r\n        // you can even nest rules inside rules\r\n        // check the Spell method called groups which lets you create routes within routes\r\n        // you can do this to validate dictionaries inside of dictionaries\r\n    }\r\n\r\n    let rules: [ValidationRule] = []\r\n\r\n    public init(build: (validator: ValidatiorBuilder) -> Void) {\r\n        let builder = ValidatorBuilder()\r\n        build(validator: builder)\r\n        self.rules = builder.rules\r\n    }\r\n\r\n    public func validate(value: Any) throws -> ValidType {\r\n        // use the rules to validate the value\r\n        // if the value is valid you can return a wrapper\r\n        // that could implement subscripts for dictionaries\r\n        // for example, to make it easier to extract the values\r\n        // this part I'm not sure if would work\r\n    }\r\n}\r\n\r\n\r\n\r\n// Usage\r\n\r\n\r\nlet validator = Validator { v in\r\n    v.integer(\"key for int\", maxValue: 10)\r\n    v.string(\"key for string\")\r\n}\r\n\r\nlet value = [\r\n    \"something\": \"something\"\r\n]\r\n\r\ndo {\r\n    let validValue = validator.validate(value)\r\n    let something = validValue[\"something\"] // returns a String, not a String? as usual\r\n} catch {\r\n    // some validation error\r\n}\r\n```\r\n\r\nNotice I never used the word *object*, because in Swift an object implies that it is an instance of a class, and we can have structs which are much more appropriate for plain data. The term used throughout is **type**, which could be a class, a struct, an enum, etc. What is usually called *object* is called value. I know this can be a bit confusing at first, but when you get used to it makes much more sense.\r\n\r\nMaybe this ideas make sense. I don't know, haha. But I guess that's how I would try to design it."}}