# @Validate

A long long time ago, in a previous life, I was a Rails developer and always loved the simplicity of the validation API. However, UIKit or SwiftUI contains no such API's (with good reason). Therefore, with every iOS and macOS project I find myself adding some kind of user input validation and every time the result feels awkward. It always feels like an after thought. 

So I figured it was time to design an API that felt more natural. 

As we are validating a property a property wrapper seemed the sensible place to start...

The easiest way to explain `[@Validate](https://github.com/reddavis/Validate)` is to show it.

```swift
import SwiftUI
import Validate


struct ContentView: View
{
    // #1
    @Validate(.presence()) var name: String = ""
    
    var body: some View {
        VStack(spacing: 60) {
            VStack {
                // #2
                TextField("Name", text: self.$name)
                    .textFieldStyle(.roundedBorder)
                    .padding()
                
                VStack {
                    // #3
                    ForEach(self._name.errors.localizedDescriptions, id: \.self) { message in
                        Text(message)
                            .foregroundColor(.red)
                            .font(.footnote)
                    }
                }
            }
            
            Button("Save") {
                // ...
            }
            .buttonStyle(.bordered)
        }
    }
}
```

There are a few things to highlight.

## #1

The `@Validate` property wrapper accepts an array of `Validation` instances. `Validation` is simply a struct that has a throwing closure for validation.

```swift
/// A struct for encapsulating validations.
public struct Validation<Value>
{
    public typealias Validate = (_ value: Value) throws -> Void
    public let validate: Validate
    
    // MARK: Initialization
    
    /// Initialize a new `Validation` instance.
    /// - Parameter validate: A `Validation.Validate` closure.
    public init(_ validate: @escaping Validate)
    {
        self.validate = validate
    }
}
```

Validate has several validation's built in such as: `.presence()`, `.format(_ pattern: String)`, `.count(greaterThan minimum: Int)`, `.count(lessThan maximum: Int)` and `.count(equalTo count: Int)`.

If the built in validations don't meet your requirements, `Validation` is public so anyone can create their own validations. This is how `.count(greaterThan minimum: Int)` is put together:

```swift
public extension Validation
{
    typealias CountGreaterThanErrorMessageBuilder = (_ minimum: Int) -> String
    
    /// Validate a collection's count is greater than a minimum amount.
    /// - Parameters:
    ///   - greaterThan: The minimum amount.
    ///   - message: Closure to build custom error message.
    /// - Returns: A Validation instance.
    static func count<T: Collection>(
        greaterThan minimum: Int,
        message: CountGreaterThanErrorMessageBuilder? = nil
    ) -> Validation<T>
    {
        .init { value in
            guard value.count > minimum else
            {
                throw ValidationError.buildGreaterThan(
                    minimum: minimum,
                    message: message
                )
            }
        }
    }
}
```

## #2

A small detail, but important if you use SwiftUI. `@Validate` acts similar to `@State` in terms that it's `projectedValue` is a `Binding`. This means you get the same benefits of `@State` but with the added feature of validation.

## #3

`Validate` exposes a `var errors: [Error]` property to access all the errors produced from validation along with a handy `var isValid: Bool`.

# Onwards

If you wanna check Validate out, you can find it over on  [Github](https://github.com/reddavis/Validate).

🍕
