# Validation and Errors Handling

## VGSTextField Input Validation

VGSCollectSDK provides built-in validation for input data and files. Validation is based on defined validation rules set for each specific `VGSTextField`. These rule sets are defined by default for each `FieldType`, but you still have possibility to customize them.

`VGSTextField` will be validating after each textfield's editing event. You can check validation results through textfield's state fields: `textfield.state.isValid` & `textfield.state.validationErrors`.

### Default Validation

Here are few examples how default validation works for specific `FieldType`:

| **FieldType**       | **Validation Details**                                                                                                                                                                                                                                                             |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **.none**           | Any input will be valid if no other validation rules will be applied                                                                                                                                                                                                               |
| **.ssn**            | US social security number, should be 9 digits, don't start with \[000,666,9] or contain sequences of the same digits. Ignores some SSNs used in advertising                                                                                                                        |
| **.cardNumer**      | Card number validation with checkSum algorithm(Luhn algorithm), available card lengths for defined card types                                                                                                                                                                      |
| **.date**           | Any date that match the selected format. By default valid date should be in `mm-dd-yyyy`                                                                                                                                                                                           |
| **.expDate**        | Any date starting from current month. By default valid expiration date should be in short year format - `MM/yy`                                                                                                                                                                    |
| **.cardHolderName** | Name, should be 2 or more symbols, valid characters shold match pattern: `[a-zA-Z0-9]`                                                                                                                                                                                             |
| **.cvc**            | card cvc number, should be 3-4 digits. If in same `VGSCollect` instance there is associated `.cardNumer` field, **cvc** validation will be dynamic. It depends on input Card Brand type. For example: for **AMEX** valid cvc only with 4 digits, while for **Visa** 3 digits only. |

If you didn't find specific `FieldType` for your use case, you can always configure `VGSTextField` with `VGSConfiguration.fieldType = .none`. Then assign any specific rule set to the field and use other configuration attributes. Check more on our code examples below.

> • To get full details about how validation rules work for each specific fields you can check `VGSCollectSDK` source code.

### Available Validation Rules

VGSCollect SDK provide pre-build validation rules that you can apply to `VGSTextField` object through it's configuration.

Here are some examples of the available rules:

| **VGSValidationRule**               | **Description**                                                                                                                                                                              |
| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| VGSValidationRuleLength             | Validate input in scope of `min` & `max` lengths                                                                                                                                             |
| VGSValidationRulePattern            | Validate input in scope of matching the regex `pattern`                                                                                                                                      |
| VGSValidationRuleDateRange          | Validate input in scope of matching date range. It also validate dates is in specific range. Supports `VGSDateFormat` date formats validation                                                |
| VGSValidationRuleCardExpirationDate | Validate input in scope of matching card expiration date format and time range. Supports `VGSCardExpDateFormat` date formats validation                                                      |
| VGSValidationRulePaymentCard        | Validate input in scope of matching supported card brands, available lengths and checkSum algorithms. Support optional validation of cards that are not defined in SDK - `CardBrand.unknown` |
| VGSValidationRuleLuhnCheck          | Validate input in scope of matching Luhn algorithm                                                                                                                                           |
| VGSValidationRuleLengthMatch        | Validate input in scope of multiple lengths, e.x.: \[16, 19]                                                                                                                                 |
| VGSValidationRuleABARoutingNumber   | Validate input against ABA (American Bankers Association) routing number requirements.                                                                                                       |

When you don't want to send to your organization vault data that is not valid, you can also set up additional `VGSConfiguration` attributes:

* **.isRequired** - if `true`, then the SDK will check if the input data in the field is **not empty** or **nil** on `VGSCollect.sendData(_:)` request. When validation failed, the DK will return a specific `VGSError` with `extraInfo` field that contains info about not valid fields.
* **.isRequiredValidOnly** - if `true`, then the SDK will check if the input data in the field is **valid** on `VGSCollect.sendData(_:)` request. When validation failed, Sthe DK will return specific `VGSError` with `extraInfo` field that contains info about not valid fields.

### How to customize VGSTextField Validation?

Here are a few examples of how to create your own validation rules set or edit existing rules that will validate input in `VGSTextField`.

Create a textfield that should be valid when input is **6-9 digits** long and starts with **555**

```swift
  let configuration = VGSConfiguration(collector: collector, fieldName: "secretNumber")
  configuration.type = .none
  configuration.formatPattern = "XXX-XXX-XXX"
  configuration.validationRules = VGSValidationRuleSet(rules: [
    VGSValidationRuleLength.init(min: 6, max: 9, error: "WRONG LENGTH"),
    VGSValidationRulePattern.init(pattern: "^555\\d*$", error: "PATTERN FAILED")
  ])
  textField.configuration = configuration
  textField.placeholder = "XXX-XXX-XXX"
```

Validate payment cards that are not supported by the SDK. In this case, all `.unknown` card types will go through `Luhn` check validation and possible card lengths.

```swift
  let cardConfiguration = VGSConfiguration(collector: collector, fieldName: "card_number")
  cardConfiguration.type = .cardNumber
  cardConfiguration.validationRules = VGSValidationRuleSet(rules:[
          VGSValidationRulePaymentCard(error: VGSValidationErrorType.cardNumber.rawValue, validateUnknownCardBrand: true)
        ])
  cardTextField.configuration = cardConfiguration
```

Validate date with format `mm/dd/yyyy` that is in a date range from `01/02/2010` and `01/02/2020`.

```swift
/// Define range validation
/// The validation will fails if the date is before 02/01/2010 or after 02/01/2020
let startDate = VGSDate(day: 2, month: 1, year: 2010)
let endDate = VGSDate(day: 2, month: 1, year: 2020)

/// Use `VGSDateConfiguration` when you need to set validation date range
let dateConfiguration = VGSDateConfiguration(
    collector: vgsCollect,
    fieldName: "date",
    datePickerStartDate: startDate,
    datePickerEndDate: endDate
)
dateConfiguration.inputDateFormat = .mmddyyyy

/// Update configuration in the text field
dateField.configuration = dateFieldConfiguration

/// Update validation rules, `start` and `end` should be the same used in the configuration `datePickerStartDate` and `datePickerEndDate`
dateConfiguration.validationRules = VGSValidationRuleSet(
    rules: [
        VGSValidationRuleDateRange(
            dateFormat: .mmddyyyy,
            error: VGSValidationErrorType.date.rawValue,
            start: startDate
            end: endDate
        )
    ]
)
```

Validate expiration date with long year format `MM/yyyy`.

```swift
  let expDateConfiguration = VGSConfiguration(collector: collector, fieldName: "exp_date")
  expDateConfiguration.type = .expDate
  expDateConfiguration.validationRules = VGSValidationRuleSet(rules: [
          VGSValidationRuleCardExpirationDate(dateFormat: .longYear, error:  VGSValidationErrorType.expDate.rawValue)
        ])
  expDateTextField.configuration = expDateConfiguration
```

Use the Input Validation results

```swift
extension ViewController: VGSTextFieldDelegate {

  func vgsTextFieldDidChange(_ textField: VGSTextField) {

    /// update textfield color on validation state changes
    textField.borderColor = textField.state.isValid ? .lightGray : .red

    /// show the validation error message
    validationLabel.text = textField.state.isValid ? "All is OK!" : textField.state.validationErrors.first
  }
}
```

### File Data validation

Before sending file data to your organization vault, `VGSCollectSDK` validates selected files.

Here are a few examples of file data validation rules:

* File source should be available for the App.
* It should be possible to convert a file into **base64**.
* File size doesn't exceed the limit of **24mb** and its size is not **0**.
* File not removed from the directory where it was selected before uploading to your organization's vault.

For each of these errors `VGSCollectSDK` will produce specific `VGSError` on `VGSCollect.sendFile(_:)`.

## Errors Handling

This guide covers error handling features that will help you make your App more reliable and recover from errors produced by `VGSCollectSDK`.

### VGSError

An object `VGSCollectSDK` used to produce errors inside the SDK. All `VGSCollectSDK` errors are produced under `VGSCollectSDKErrorDomain` domain.

#### Declaration

```swift
class VGSError: NSError
```

#### Attributes

| **Attribute**             | **Type/Description**                                     |
| ------------------------- | -------------------------------------------------------- |
| key                       | **String**, error key defined in `VGSErrorInfoKey.swift` |
| NSLocalizedDescriptionKey | **String**, error description for developer              |
| extraInfo                 | **Dictionary**, can contain additional error details     |

`VGSError` inherits iOS native `NSError` class and works similar. `VGSError` populates error codes, declared in `VGSErrorType`, and error keys, declared in [VGSCollectSDK Reference docs](https://verygoodsecurity.github.io/vgs-collect-ios/Error%20Keys.html).

#### Error codes

List of Error codes produced by VGS Collect iOS SDK locally.

| **Code** | **Key**                        | **Description**                                        |
| -------- | ------------------------------ | ------------------------------------------------------ |
| 1001     | `inputDataIsNotValid`          | When input data is not valid, but required to be valid |
| 1101     | `inputFileNotFound`            | When can't find file on device                         |
| 1102     | `inputFileTypeIsNotSupported`  | When selected file type not supported                  |
| 1103     | `inputFileSizeExceedsTheLimit` | When file size is larger then allowed limit            |
| 1150     | `sourceNotAvailable`           | When can't get access to file source                   |
| 1400     | `unexpectedResponseType`       | When response type is not supported                    |
| 1401     | `unexpectedResponseDataFormat` | When response data format is not supported             |
| 1480     | `invalidConfigurationURL`      | When VGS configuration URL is not valid                |
| 1300     | `invalidAccessToken`           | When access token is nil or empty                      |

#### Code example

```swift
vgsCollect.sendData(path: "/post", extraData: nil) { [weak self](../../response) in
  
  switch response {
  case .failure(let code, _, _, let error):
    switch code {
    /// Hande not valid fields data error
    case VGSErrorType.inputDataIsNotValid.rawValue:
      /// handle error
    /// ...
    return
  }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/ios-sdk/error-handling.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
