Passing Events Using iOS SDK

Passing data in async mode

Call the Mindbox.shared.executeAsyncOperation SDK method to send async data to Mindbox.

This method accepts:

  • API method system name,
  • Mindbox request body.

Method description

executeAsyncOperation<T: OperationBodyRequestType>(
  operationSystemName: String, 
  operationBody: T
)

Call example

let body = OperationBodyRequest()

body.customer =  .init(
  email: "<Email>",
  mobilePhone: "<Cell phone>",
  ids:  ["websiteid": "<Website ID"],
  subscriptions: [
    .init(
      brand: "<System name of the brand a customer is subscribed to>",
      pointOfContact: .sms,
      topic: "<External ID of the subscription topic>",
      isSubscribed: true
    )
  ]

)

Mindbox.shared.executeAsyncOperation(
  operationSystemName: "Mobile.AuthorizeCustomer",
  operationBody:body
)

Passing and receiving data in sync mode

Call the Mindbox.shared.executeSyncOperation method to execute operations in sync mode.

This method accepts as arguments:

  • API method system name,
  • Mindbox request body,
  • the callback to request if the operation is completed successfully,
  • the callback to request if the operation is completed with an error.

Such callbacks have a typed object into which Mindbox’s response is parsed.

If the SDK’s methods fail to process Mindbox’s response, create your own class to process responses. This class is passed as a separate parameter into the function call.

Using a predefined class

Method description

public func executeSyncOperation<T>(
  operationSystemName: String,
  operationBody: T,
  completion: @escaping (Result<OperationResponse, MindboxError>) -> Void
) where T: OperationBodyRequestType {}

Here, the call uses operationSystemName and operationBody as parameters. The Result<OperationResponse, MindboxError> entity is returned in response.

Example

// Create body
let body = OperationBodyRequest()
body.productListItems = ... // fill with data

// Call method
Mindbox.shared.executeSyncOperation(
 operationSystemName: "OperationName",
 operationBody: body
) { result in
  switch result {
    case let .success(response):
      // Handle response here
    case let .failure(error):
      print(error.errorDescription)
  }
}

Using a custom response class

Here, the call uses operationSystemName, operationBody, and customResponseType as parameters. The customResponseType parameter should implement the OperationResponseType protocol, and the expected response is a Result<P, MindboxError> entity.

Method description

public func executeSyncOperation<T, P>(
  operationSystemName: String,
  operationBody: T,
  customResponseType: P.Type,
  completion: @escaping (Result<P, MindboxError>) -> Void
) where T: OperationBodyRequestType, P: OperationResponseType {}

Example

// Create a new struct/class wich implements OperationResponseType 
struct MyResponse: OperationResponseType {
  var status: Status

  // provide custom fields here
}

...

// Create body
let body = OperationBodyRequest()
body.productListItems = ... // fill with data

// Call method
Mindbox.shared.executeSyncOperation(
  operationSystemName: "OperationName",
  operationBody: body,
  customResponseType: MyResponse.self // type of your custom response model
) { result in
   switch result {
     case let .success(response):
     // handle response here
     // response is type of MyResponse
     case let .failure(error):
     print(error.errorDescription)
   }
  }

Response definitions

OperationResponse is a model listing all the fields that a server might return. All these fields are optional.

MindboxError is an error model that Mindbox returns. Server errors could be:

  • validationError that contains the ValidationError model. This refers to fields with incorrect values;
  • protocolError that contains the ProtocolError model, returned for server responses with a 4XX status or for certain 5XX errors;
  • serverError that is returned for a 5ХХ status response without data from the server;
  • connectionError that is a request error due to a connection failure;
  • invalidResponse that is returned for an invalid server response;
  • internalError that refers to Mindbox’s configuration errors, response decoding errors, etc.;
  • unknown that is returned for unexpected behavior when the nested type is Error.

Use the errorDescription parameter for debugging.

Call body constructor

Use the OperationBodyRequestType to create a call body in Mindbox.

To implement OperationBodyRequestType and populate all the standard call fields, use the OperationBodyRequest call body constructor. This will simplify integration with the SDK.

Using the constructor: a detailed example

let body = OperationBodyRequest()

body.viewProduct = .init(
    productGroup: .init(ids: ["website": "test-1"]),
    customerAction: .init(customFields: ["string": "test"])
)

Extended example with customer data

func createCustomer(
  email: String,
  phone: String,
  userId: String
) -> OperationBodyRequest {
  let body = OperationBodyRequest()
  let dateFormatter = DateFormatter()

  dateFormatter.dateFormat = "dd.MM.yyyy"
  let birthDate = dateFormatter.date(from: "12.01.1998")

  body.customer = .init(
    birthDate: birthDate?.asDateOnly,
    sex: .male,
    firstName: "<Name>",
    email: email,
    mobilePhone: phone,
    ids: ["websiteId": userId],
    customFields: [
      "firstField": "<additional field 1>", 
      "secondField": "<additional field 2>"
    ],
    subscriptions: [
      .init(
        brand: "<brand>",
        pointOfContact: .email,
        isSubscribed: true
      ),
      .init(
        brand: "<brand>",
        pointOfContact: .sms,
        topic: "<subscription topic>",
        isSubscribed: true
      ),
    ]
  )

  return body
}

Mindbox.shared.executeAsyncOperation(
  operationSystemName: name.rawValue, 
  operationBody: createCustomer("[email protected]", "12025550159", "Test")
)

If the required fields are missing in the call body constructor, create your own custom class which inherits from the OperationBodyRequest class and override the encode method.

class CustomOperationBodyRequest: OperationBodyRequest {
  var field: String?

  // override this method when using inheritance
  override func encode(to encoder: Encoder) throws {
    // call super.encode(to:)
    try super.encode(to: encoder)
    var container = encoder.container(keyedBy: Keys.self)

    // encode to container new fields
    try container.encode(field, forKey: .field)
  }

  // provide keys for encoding
  enum Keys: String, CodingKey {
    case field
  }
}