# File Uploader

VGS Collect provides an interface for collecting and sending file data to **VGS**.\
You can add a file uploading functionality to your application with `VGSFilePickerController`.

## VGSFilePickerController

An object you use to import files from `VGSFileSource`.

### Declaration

```swift
class VGSFilePickerController
```

### Creating a VGSFilePickerController

```swift
required init(configuration: VGSFilePickerConfiguration)
```

> • You can to select and send only one file at a time.\
> • You should always create **strong** referrence for **VGSFilePickerController** instance inside your **UIViewController**.

### VGSFilePickerController Attributes and Methods

```swift
/// Handle VGSFilePickerController states
var delegate: VGSFilePickerControllerDelegate?

/// Present File Picker object on a *UIViewController*
func presentFilePicker(on viewController: UIViewController, animated: Bool, completion: (() -> Void)? = nil)

/// Dismiss File Picker from a *UIViewController*
func dismissFilePicker(animated: Bool, completion: (() -> Void)? = nil)
```

## VGSFilePickerControllerDelegate

### Declaration

```swift
@objc protocol VGSFilePickerControllerDelegate
```

### Managing Controller States

```swift
/// On user did finish picking file
@objc func userDidPickFileWithInfo(_ info: VGSFileInfo)

/// On user did Cancel file picking
@objc func userDidSCancelFilePicking()

/// On error occured during file picking
@objc optional func filePickingFailedWithError(_ error: VGSError)
```

> • When picked file is valid, it will be stored in **VGSCollect** storage.\
> • **VGSFileInfo** contains optional file metadata info. SDK don't validate file metadata info.\\

### VGSFileSource

Type of file source

| **VGSFileSource**       | **Description**        |
| ----------------------- | ---------------------- |
| **.camera**             | Device camera          |
| **.photoLibrary**       | Device photoLibrary    |
| **.documentsDirectory** | Device files directory |

## Send File

You should use`VGSCollect` object functions to send file data to your organization's vault.

```swift
/**
  Send file attached to VGSCollect insatnce to your organization vault.
  
  - Parameters:
    - path: Inbound rout path for your organization vault.
    - method: HTTPMethod, default is `.post`.
    - routeId: id of VGS Proxy Route, default is `nil`.
    - extraData: Any data you want to send together with data from VGSTextFields , default is `nil`.
    - requestOptions: `VGSCollectRequestOptions` object, holds additional request options. Default options are `.nestedJSON`.
    - completion: response completion block, returns `VGSResponse`.
  
  - Note:
    Errors can be returned in the `NSURLErrorDomain` and `VGSCollectSDKErrorDomain`.
*/
public func sendFile(path: String,
                    method: HTTPMethod = .post,
                  routeId: String? = nil,
                extraData: [String: Any]? = nil,
            requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions(),
          completion block: @escaping (VGSResponse) -> Void)


/**
  Asynchronously send file attached to VGSCollect insatnce to your organization vault.
*/
public func sendFile(path: String,
                    method: HTTPMethod = .post,
                  routeId: String? = nil,
                extraData: [String: Any]? = nil,
            requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions()) async throws -> VGSResponse

/**
  Send file attached to VGSCollect insatnce to your organization vault using the Combine framework.
*/
public func sendFilePublisher(path: String,
                    method: HTTPMethod = .post,
                  routeId: String? = nil,
                extraData: [String: Any]? = nil,
            requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions()) -> Future<VGSResponse, Never> 
```

Errors can be returned in the `NSURLErrorDomain` and `VGSCollectSDKErrorDomain`.\
You will receive **VGSError** on `sendFile(_:)` request if the input file data is not supported or doesn't meet the size limits. For more details, check [SDK Reference Docs](https://verygoodsecurity.github.io/vgs-collect-ios/Errors.html).

### Remove file from VGSCollect storage.

After the file is selected by the user, it will be stored in the App memory and connected to `VGSCollect` storage instance. It's your responsibility to detach the file from the **VGSCollect** instance after sending the file. Use **vgsCollect.cleanFiles()** to detach files whenever you need.

```swift
/// remove files from VGSCollect storage
func cleanFiles()
```

> • Only file data and extraData will be sent to **VGS** on **vgsCollect.sendFile(\_:)**. If you need to send data from **VGSTextField** use **vgsCollect.sendData(\_:)** instead.\
> • The max file size that can be send to **VGS** is **24 Mb**. You will get specific **VGSError** when file size exceeds the limit.\\

## Usage

*Send data to your organization's vault*

```swift
/// Inside your ViewController create and configure *strong* referrence of ``VGSFilePickerController`` instance:

class FilePickerViewController: UIViewController {

  // Create strong referrence of VGSFilePickerController
  var pickerController: VGSFilePickerController?

  // Collector vgs
  var vgsCollect = VGSCollect(id: "<VAULT_ID>", environment: .sandbox)


  override func viewDidLoad() {
      super.viewDidLoad()

      // create picker configuration
      let filePickerConfig = VGSFilePickerConfiguration(collector: vgsCollect, fieldName: "secret_doc", fileSource: .photoLibrary)

      // init picket controller with configuration
      pickerController = VGSFilePickerController(configuration: filePickerConfig)

      // handle picker delegates
      pickerController?.delegate = self
  }


  @IBAction func sendAction(_ sender: Any) {
        let extraData = ["document_holder": "Joe B"]

        /// send data to your Vault
        vgsCollect.sendFile(path: "/post", method: .post, extraData: extraData) { [weak self](../../response) in
          switch response {
            case .success(let code, let data, let response):
              // parse data
            case .failure(let code, let data, let response, let error):
              // handle failed request
              switch code {
                // handle error codes
              }
          }
        }
    }

  // Present picker controller
  private func selectFileFromSource() {
      pickerController?.presentFilePicker(on: self, animated: true, completion: nil)
  }
}
```

*Asynchronously send the file attached to the VGSCollect instance to your organization's vault using the Combine framework.*

```swift
  do {
    let response = try await vgsCollect.sendFile(path: "/post", method: .post)
    switch response {
      case .success(let code, let data, let response):
        // parse data
      case .failure(let code, let data, let response, let error):
        // handle failed request
        switch code {
          // handle error codes
        }
    }
  } catch {
    // handle error
  }
```

*Send the file attached to the VGSCollect instance to your organization's vault using the Combine framework.*

```swift
  vgsCollect.sendFilePublisher(path: "/post", method: .post)
    .sink { completion in
      switch completion {
        case .finished:
          // handle finished
        case .failure(let error):
          // handle error
      }
    } receiveValue: { response in
      // parse data
    }
    .store(in: &cancellables)
```

Handle `VGSFilePickerController` states with `VGSFilePickerControllerDelegate`.

```swift

extension FilePickerViewController: VGSFilePickerControllerDelegate {

  // Check file info, selected by user
  func userDidPickFileWithInfo(_ info: VGSFileInfo) {
      let fileInfo = """
                    File info:
                    - fileExtension: \(info.fileExtension ?? "unknown")
                    - size: \(info.size)
                    - sizeUnits: \(info.sizeUnits ?? "unknown")
                    """
      print(fileInfo)
      pickerController?.dismissFilePicker(animated: true)
  }

  // Handle cancel file selection
  func userDidSCancelFilePicking() {
      pickerController?.dismissFilePicker(animated: true)
  }

  // Handle errors on picking the file
  func filePickingFailedWithError(_ error: VGSError) {
      pickerController?.dismissFilePicker(animated: true)
  }
}
```


---

# 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/files-upload.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.
