Collect and Send Data

Collect and Send Data

With the VGS Collect SDK, you can tokenize data via the Vault API or securely send it to your server using the VGS Proxy.

Send Data to Your Server via VGS Proxy

Using the sendData(_:) method, sensitive data from VGSTextField will be collected, stored in your organization's Vault, and sent to the Upstream URL specified in the Inbound Route.

/**
  Send data from VGSTextFields 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 sendData(path: String,
                    method: HTTPMethod = .post,
                  routeId: String? = nil,
                extraData: [String: Any]? = nil,
            requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions(),
          completion block: @escaping (VGSResponse) -> Void)

/**
  Asynchronously send data from VGSTextFields to your organization vault.
*/
public func sendData(path: String,
                    method: HTTPMethod = .post,
                  routeId: String? = nil,
                extraData: [String: Any]? = nil,
            requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions()) async throws -> VGSResponse

/**
  Send data from VGSTextFields to your organization vault using the Combine framework.
*/
public func sendDataPublisher(path: String,
                    method: HTTPMethod = .post,
                  routeId: String? = nil,
                extraData: [String: Any]? = nil,
            requestOptions: VGSCollectRequestOptions = VGSCollectRequestOptions()) -> Future<VGSResponse, Never> 

The send data request returns VGSResponse.failure(_:) in the following cases: • The response status code is invalid (i.e., not in the range [200..<300]). • The request is not possible due to iOS system conditions (e.g., no internet connection). • The data being sent is invalid according to VGSConfiguration.\

Errors can be returned in the NSURLErrorDomain and VGSCollectSDKErrorDomain. For more details, check the SDK Reference Docs.

• Data will be collected from all text fields that registered to current VGSCollectinstance and send to your organization vault id. • By default aliases are not a part of response data for sendData(_:) request. It's your responsibility to configure a response for the client after the data goes through the Inbound Proxy to your backend. However, if you test sendData(_:) request with our echo server, you will get a response with the same body as in the request, where the raw data will be redacted to aliases.

Code example

Send data to your organization vault:

func sendData(_ sender: UIButton) {

    /// extra information can be sent together with all sensitive data from VGSTextFields
    var extraData = [String: Any]()
    extraData["cardHolderName"] = "Joe Business"

    /// send data to your Vault
    vgsCollect.sendData(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
          }
      }
    }
}

Asynchronously send data from VGSTextFields to your organization vault:

func sendData() async {
    do {
      let response = try await vgsCollect.sendData(path: "/post", method: .post)
      switch respose {
        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 data from VGSTextFields to your organization vault using the Combine framework:

  vgsCollect.sendDataPublisher(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)

• If you need to send files data, check VGSFilePickerController.

Sending custom data

To send additional custom data, include it in the extraData parameter of the sendData(_:)` request.

Code example

// ...

/// extra information can be sent together with all sensitive data from VGSTextFields
var extraData = [String: Any]()
extraData["cardHolderName"] = "Joe Business"

/// send data to your Vault
vgsCollect.sendData(path: "/post", extraData: extraData) { [weak self](../../response) in
  switch response {
    // ...
  }
}

Setting Custom API Headers

To include custom headers in your sendData(_:) request, assign them to:

var customHeaders: [String: String]?

Code example

// ...

/// set custom headers
vgsCollect.customHeaders = [
    "custom header": "custom data"
]

VGSResponse

Represents the result of a VGS SDK request.

Declaration

@frozen enum VGSResponse

    /// Success response case
    case success(_ code:Int, _ data:Data?, _ response: URLResponse?)

    /// Failed response case
    case failure(_ code:Int, _ data:Data?, _ response: URLResponse?, _ error:Error?)

See SDK Reference Docs for more information.

Advanced Settings

Setting Custom JSON Structure

Use dot (.) notation in the VGSConfiguration.fieldName to define nested JSON structures. Each dot (.) in a fiealdName will create a new level of nesting.

Code example

/// Define field names
let userId = "userId"
let cardNumberFieldKey = "card_data.card_number"
let cardCVCFieldKey = "card_data.cvc"

/// Example of transformed JSON structure on sendData(_:)
{
  "userId": "id12345",
  “card_data: {
     “card_number”:  411111111111111”,
     “cvc”: “123”
  }”
}

• If there are two fieldNames with equal names - they will be overwritten. • If object structure and field name in extraData are same as defined in VGSConfiguration fieldName, value in extraData will be overwritten by data collected from VGSCollect elements with same name on sendData(_:).

Dot (.) notation does not apply to extraData keys. You must format extraData as desired before passing it to sendData(_:).

Nested JSON with array

Use [index] notation in fieldName888 to represent arrays. Only one key with an array index is supported per level. Multi-dimensional arrays are not supported.

Field Mapping Policies:

  • nestedJSON - map fieldnames with dot notation to nested JSON. Arrays are not supported. Is default policy.

  • flatJSON - map fieldNames to JSON. Flat JSON format uses fieldname as a single key and does not produce any nested JSON or array.

  • nestedJSONWithArrayOverwrite - map fieldnames with dot notation to nested JSON and arrays. Replace extraData the array with the VGS Collect array.

  • nestedJSONWithArrayMerge - map fieldnames with dot notation to nested JSON and arrays. Merge VGS Collect and extraData array.

Specify fieldName mapping policy with VGSCollectRequestOptions on sendData(_:).

/// Define field names
let cardNumberFieldKey = "card_data[0].number"
let cardCVCFieldKey = "card_data[1].cvc"

let vgsCollect = VGSCollect(id: "<VAULT_ID>", environment: .sandbox, dataRegion: "eu-1")
var options = VGSCollectRequestOptions()
options.fieldNameMappingPolicy = .nestedJSONArrayOvewrite
// Or
options.fieldNameMappingPolicy = .nestedJSONArrayMerge

vgsCollect.sendData(path: "/post", requestOptions: options) { requestResult in }

Example of transformed JSON structure on sendData(_:)

{
  "card_data" :
  [
    { "number" :  "411111111111111"},
    {"cvc": "123"}
  ]
}

Check more examples how to customize JSON structure.

If you need to change the output value format, you can read more about available functionality in VGSConfiguration section.

Tokenize data

VGS offers two Vault API versions for data tokenization: • Vault API v1: Uses tokenizeData(_:). Learn more. • Vault API v2: Uses createAliases(_:) and requires Authorization. Learn more. Each API version requires an appropriate Upstream URL specified in your Vault's Route configuration.\

• Vault API v2 is our newest Vault API and is recommended for integrations. • If you already use API v1 you can find migration guide to API v2 below.

Makes a tokenization request to Vault API v2 with data from VGSTextFields:

public func createAliases(routeId: String? = nil, completion block: @escaping (VGSTokenizationResponse) -> Void)

Asynchronously makes a tokenization request with data from VGSTextFields:

public func createAliases(routeId: String? = nil) async throws -> VGSTokenizationResponse

Makes a tokenization request with data from VGSTextFields using the Combine framework:

public func createAliasesDataPublisher(routeId: String? = nil) -> Future<VGSTokenizationResponse, Never>

VGSTokenizationResponse

An object you use to handle SDK tokenization request completion.

Declaration

@frozen public enum VGSTokenizationResponse {
    /**
     Success response case

     - Parameters:
        - code: response status code.
        - body: response **JsonData** object.
        - response: URLResponse object represents a URL load response.
    */
  case success(_ code: Int, _ body: JsonData?, _ response: URLResponse?)

    /**
     Failed response case

     - Parameters:
        - code: response status code.
        - data: response **Data** object.
        - response: `URLResponse` object represents a URL load response.
        - error: `Error` object.
    */
    case failure(_ code: Int, _ data: Data?, _ response: URLResponse?, _ error: Error?)
}

Code example

Send tokenization request with data from VGSTextFields to your organization vault:

You should set authToken into VGSCollect customHeaders before calling the createAliases(:) function:

vgsCollect.customHeaders = ["Authorization": "Bearer (authToken)"]
vgsCollect.createAliases{ [weak self](response) in
  switch response {
  case .success(_, let resultBody, _):
    let response = (String(data: try! JSONSerialization.data(withJSONObject: resultBody!, options: .prettyPrinted), encoding: .utf8)!)
      print(response)
      return
  case .failure(let code, _, _, let error):
    switch code {
    case 400..<499:
      // Wrong request. This also can happend when your Routs not setup yet or your <vaultId> is wrong
    case VGSErrorType.inputDataIsNotValid.rawValue:
      if let error = error as? VGSError {
        self?.consoleLabel.text = "Error: Input data is not valid. Details:
 (error)"
      }
    default:
      self?.consoleLabel.text = "Error: Something went wrong. Code: (code)"
    }
    print("Submit request error: (code), (String(describing: error))")
    return
  }
}

Send tokenization request with data from VGSTextFields to your organization vault using the async/await:


do {
  let response = try await vgsCollect.createAliases()
  switch respose {
    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 toa kenization request with data from VGSTextFields to your organization's vault using the Combine framework:


  vgsCollect.createAliasesDataPublisher()
    .sink { completion in
      switch completion {
        case .finished:
          // handle finished
        case .failure(let error):
          // handle error
      }
    } receiveValue: { response in
      // parse data
    }
    .store(in: &cancellables)

  • Data will be collected from all VGSTextFields registered to current VGSCollectinstance. - Only data from VGSTextFields configured with one of available tokenization configurations will be tokenized and stored in your's organization vault. - Data from VGSTextFields configured with other configuration types will be returned as raw value along with tokenized data in VGSTokenizationResponse. - Data from fields with type .cvc and .cardNumber will not be included to VGSTokenizationResponse if tokenization configurations not set for appropriate fields.

RouteId

The route identifier specifies how data should be routed in your organization's vault. You should follow the next rules when setting routeId:

  • You should set specific routeId when you use multiple routes in your organization's vault.

  • RouteId should be a valid UUID string; you will receive an error in VGSTokenizationResponse in case if it's not valid.

  • If you have only one Inbound Route in your organization's vault, you can leave routeId as nil.

Migrating from Vault API v1 to v2

Migration from Vault API v1 to API v2 will require you to implement the next steps:

  • Update your organization's Vault Route with a new Upstream Host: use https://<your-vault-id>.sandbox.vault-api.verygoodvault.com for sandbox or https://<your-vault-id>.live.vault-api.verygoodvault.com for a live environment.

  • Receive Tokenization authToken from your backend and set it in VGSCollect headers: vgsCollect.customHeaders = ["Authorization": "Bearer \(authToken)"].

  • Use -createAliases(:) function instead of -tokenize(:) creating aliases.

For more details about available attributes and functionality, check VGSCollectSDK Reference docs

Last updated