Sending Events via iOS SDK

Submitting async data to Maestra

Run the Mindbox.shared.executeAsyncOperation SDK method to submit async data to Maestra.

This SDK method receives:

  • the system name of the operation;
  • the body of the request to Maestra.

Method description

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

Example

let body = OperationBodyRequest()

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

)

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

Submitting and receiving synced data from Maestra

Run Mindbox.shared.executeSyncOperation to execute synced operations.

This SDK method takes as parameters:

  • the system name of the method;
  • the request body;
  • the callback for successful operations;
  • the callback for unsuccessful operations.

A typed object is passed to the callbacks, with the Maestra response parsed into it.

You can also create your own class to process Maestra’s responses if processing cannot be carried out using the SDK’s structures. This class should be passed to the function call as an individual parameter.

Using a predefined class

Method description

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

Use the operationSystemName and operationBody parameters to make a request.

The request response is the Result<OperationResponse, MindboxError> entity.

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 your own class in response

In this case, the request requires operationSystemName, operationBody, and customResponseType (which must implement the OperationResponseType protocol).
The response is returned as Result<P, MindboxError>.

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 Maestra 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 5XX 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 Maestra’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.

Request body constructor

Use the OperationBodyRequestType to create a request body in Maestra.

To simplify integration, the SDK provides the OperationBodyRequest request body constructor, which implements this structure and allows you to populate all standard request fields.

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 request 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
  }
}