Using protocols to display different types of json responses from the server

Assume you have the following json. If you notice carefully, the data is almost similar to each other. Our goal is to give us a single data structure, which will store the details shown here.

var deposit = """
{
  "channelName": "Deposit",
  "withdrawableBalance": 1000,
  "accounts": [
    {
      "accountId": "122xeeweX",
      "bank": "wells fargo",
      "withdrawableBalance": 1000
    }
  ]
}
"""

var withdraw = """
{
  "channelName": "Withdraw",
  "accounts": [
    {
      "accountId": "122xeeweX",
      "bank": "wells fargo",
      "withdrawableBalance": 1000
    },
    {
      "accountId": "12wwwewWWxeeweX",
      "bank": "WIRE",
      "withdrawableBalance": 1000,
      "createdDate": 1663727163000
    }
  ]
}
"""

var buy = """
{
  "channelName": "Buy",
  "buyLimit": 1000,
  "minimumBuyAmount": 10,
  "accounts": [
    {
      "accountId": "122xeeweX",
      "bank": "wells fargo",
      "buy": 1000
    }
  ]
}
"""

To begin with, let’s define a protocol

protocol Transaction {
    var channelName: String { get }
}
           

Let’s define the Codable object for these responses. You can easily convert the string into a Codable object using the tool here https://app.quicktype.io/

// MARK: - Deposit
struct Deposit: Codable, Transaction {
    let channelName: String
    let withdrawableBalance: Int?
    let accounts: [Account]?
}

// MARK: - Account
struct Account: Codable {
    let accountID, bank: String?
    let withdrawableBalance: Int?

    enum CodingKeys: String, CodingKey {
        case accountID = "accountId"
        case bank, withdrawableBalance
    }
}


// MARK: - Buy
struct Buy: Codable, Transaction {
    let channelName: String
    let buyLimit, minimumBuyAmount: Int?
    let accounts: [BuyAccount]?
}

// MARK: - Account
struct BuyAccount: Codable {
    let accountID, bank: String
    let buy: Int?

    enum CodingKeys: String, CodingKey {
        case accountID = "accountId"
        case bank, buy
    }
}

// MARK: - Withdraw
struct Withdraw: Codable, Transaction {
    let channelName: String
    let accounts: [WithdrawAccount]?
}

// MARK: - Account
struct WithdrawAccount: Codable {
    let accountID, bank: String?
    let withdrawableBalance, createdDate: Int?

    enum CodingKeys: String, CodingKey {
        case accountID = "accountId"
        case bank, withdrawableBalance, createdDate
    }
}

Now let’s define the actual method to decode this json. You can notice we have a single return type called Transaction.

struct ResponseDecoder {
    func decode(_ response: String, for intent: Int) -> Transaction? {
        do {
            let jsonData = response.data(using: .utf8)!
            let jsonDecoder = JSONDecoder()
            var transaction: Transaction
            switch intent {
            case 0:
                transaction = try jsonDecoder.decode(Withdraw.self, from: jsonData)
                return transaction
            case 1:
                return try jsonDecoder.decode(Buy.self, from: jsonData)
            case 2:
                return try jsonDecoder.decode(Deposit.self, from: jsonData)
            default:
                return nil
            }
            
        } catch {
            print("error decoding string")
        }
        return nil
    }
}

Display the data as shown below

struct DisplayAllData {
    func display() {
        guard let withdrawResponse = ResponseDecoder().decode(withdraw, for: 0) else {
            return
        }
        print(withdrawResponse.channelName)
        guard let buyResponse = ResponseDecoder().decode(buy, for: 1) else {
            return
        }
        print(buyResponse.channelName)
        guard let depositResponse = ResponseDecoder().decode(deposit, for: 2) else {
            return
        }
        print(depositResponse.channelName)
    }
}

DisplayAllData().display()

In

,

Leave a Reply

Your email address will not be published. Required fields are marked *