简体   繁体   中英

Swift 5 Json Parse from post Request

I am trying to parse JSON data from a post request and I am struggling with the outcome. I would like to parse the JSON data in the Swift 5 programming language.

I have spent hours trying to figure this out. I am very confused on how to deal with multiple levels of hiarchy like this.

I dont need all the data i just need time and total_amount_sent.

Swift

struct Response: Codable {
    var txs: [ResponseData]

    enum CodingKeys: String, CodingKey {
        case txs
    }
    
}

struct ResponseData: Codable {
    var time: String?
    var total_amount_sent: String?
    var recipient: String?
    var txid: String?
    var amount: String?
 
}

        let url = URL(string: paramURL)!
        let json: [String: Any] = [
            "key": "value"
        ]
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = try? JSONSerialization.data(withJSONObject: json)
        let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in
            
            do {
                let json = try JSONDecoder().decode(Response.self, from: data!)
                
                print(json)
                
               json.txs.forEach { charge in
                
                let transaction_time = charge.time
                let transaction_txid = charge.txid
                let transaction_total_amount_sent = charge.total_amount_sent
                
                print(transaction_time)
                print(transaction_txid)
                print(transaction_total_amount_sent)
                
                
               
               }
          
            } catch {
               print("Error! \(error)")
            }
     
        
        })
        task.resume()

Error:

Error: keyNotFound(CodingKeys(stringValue, "txs": intValue, nil). Swift.DecodingError:Context(codingPath, []: debugDescription: "No value associated with key CodingKeys(stringValue, "txs": intValue. nil) ("txs"),": underlyingError: nil))

JSON:

{
  "status" : "success",
  "data" : {
    "network" : "DOGETEST",
    "txs" : [
      {
        "txid" : "df4ac3ecfc356d9e10325cd4043a4103602599b71a91ea96cb3fa3204c61264c",
        "from_green_address" : false,
        "time" : 1620076250,
        "confirmations" : 5,
        "amounts_received" : [
          {
            "recipient" : "2N3ZbAaJqtxD5jfbLDZichV6SSHZ6PBYPmi",
            "amount" : "2.00000000"
          }
        ],
        "senders" : [
          "2MtSgfBmXzZv6raD7yyuGzFamzBzQD7G6Rf"
        ],
        "confidence" : 1.0,
        "propagated_by_nodes" : null
      },
      {
        "txid" : "d983739751a6170d336016ffa1b7d7f2849a4a81cb0021e03a2cc6d76c55379d",
        "from_green_address" : false,
        "time" : 1620076071,
        "confirmations" : 6,
        "amounts_received" : [
          {
            "recipient" : "2N3ZbAaJqtxD5jfbLDZichV6SSHZ6PBYPmi",
            "amount" : "2.00000000"
          }
        ],
        "senders" : [
          "2MtSgfBmXzZv6raD7yyuGzFamzBzQD7G6Rf"
        ],
        "confidence" : 1.0,
        "propagated_by_nodes" : null
      },
      {
        "txid" : "1dce7dd99f6a655ca82a94c8e088576c78e4ece94995f2f90891b8f5f31a54db",
        "from_green_address" : false,
        "time" : 1620076021,
        "confirmations" : 6,
        "amounts_received" : [
          {
            "recipient" : "2N3ZbAaJqtxD5jfbLDZichV6SSHZ6PBYPmi",
            "amount" : "8.00000000"
          }
        ],
        "senders" : [
          "2MtSgfBmXzZv6raD7yyuGzFamzBzQD7G6Rf"
        ],
        "confidence" : 1.0,
        "propagated_by_nodes" : null
      },
      {
        "txid" : "27719e8fae3bb64f1ecec8ac64a2135d1ccc5d9219040dceaec9d24e4b17a466",
        "from_green_address" : false,
        "time" : 1620075780,
        "confirmations" : 6,
        "amounts_received" : [
          {
            "recipient" : "2N3ZbAaJqtxD5jfbLDZichV6SSHZ6PBYPmi",
            "amount" : "4.00000000"
          }
        ],
        "senders" : [
          "2MtSgfBmXzZv6raD7yyuGzFamzBzQD7G6Rf"
        ],
        "confidence" : 1.0,
        "propagated_by_nodes" : null
      },
      {
        "txid" : "2a6547411b15442b78b118981cf5632e3faedec8941aea22453d8837807d37be",
        "from_green_address" : false,
        "time" : 1620075743,
        "confirmations" : 7,
        "amounts_received" : [
          {
            "recipient" : "2N3ZbAaJqtxD5jfbLDZichV6SSHZ6PBYPmi",
            "amount" : "2.00000000"
          }
        ],
        "senders" : [
          "2MtSgfBmXzZv6raD7yyuGzFamzBzQD7G6Rf"
        ],
        "confidence" : 1.0,
        "propagated_by_nodes" : null
      },
      {
        "txid" : "63a145cbdc48c1e644fa52a30ed26d66c58b685698104a549001d0fe539816ba",
        "from_green_address" : false,
        "time" : 1620075697,
        "confirmations" : 7,
        "amounts_received" : [
          {
            "recipient" : "2N3ZbAaJqtxD5jfbLDZichV6SSHZ6PBYPmi",
            "amount" : "4.00000000"
          }
        ],
        "senders" : [
          "2MtSgfBmXzZv6raD7yyuGzFamzBzQD7G6Rf"
        ],
        "confidence" : 1.0,
        "propagated_by_nodes" : null
      },
      {
        "txid" : "ff350583e0cb1396a3d5cc09350697daf111626ec5a3b893f8e936276f1c6715",
        "from_green_address" : false,
        "time" : 1620075677,
        "confirmations" : 7,
        "amounts_received" : [
          {
            "recipient" : "2N3ZbAaJqtxD5jfbLDZichV6SSHZ6PBYPmi",
            "amount" : "2.00000000"
          }
        ],
        "senders" : [
          "2MtSgfBmXzZv6raD7yyuGzFamzBzQD7G6Rf"
        ],
        "confidence" : 1.0,
        "propagated_by_nodes" : null
      },
      {
        "txid" : "5a0115a9f608f3d01caee03587253fc58e0ad0c602f4e95e6c0db1e11703af84",
        "from_green_address" : false,
        "time" : 1619998414,
        "confirmations" : 227,
        "amounts_received" : [
          {
            "recipient" : "2N3ZbAaJqtxD5jfbLDZichV6SSHZ6PBYPmi",
            "amount" : "1000.00000000"
          }
        ],
        "senders" : [
          "2MytwDpHWpdoVYQ7JzYwBPxQ5XsEdiV7udZ"
        ],
        "confidence" : 1.0,
        "propagated_by_nodes" : null
      }
    ]
  }
}

Your model was not properly structured.

struct Response: Decodable {
    var txs: [ResponseData]

    enum CodingKeys: CodingKey {
        case data
    }
    enum ValueCodingKeys: CodingKey {
        case txs
    }
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let nestedContainer = try container.nestedContainer(keyedBy: ValueCodingKeys.self, forKey: .data)
        txs = try nestedContainer.decode([ResponseData].self, forKey: .txs)
    }
    
}

struct ResponseData: Decodable {
    var time: Int?
    var txid: String?

    var amountsReceived: [AmoutReceived]
}


struct AmoutReceived: Decodable {
    var recipient: String?
    var amount: String?
}

Use .convertFromSnakeCase . Hope you are handling error cases properly. Here is the code

func fetch(urlString: String, callback: @escaping (Result<Response, Error>) -> Void) {
    guard let url = URL(string: urlString) else { return }

    URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard let data = data else {
            if let error = error {
                callback(.failure(error))
            }
            return
        }
        do {
            let decoder = JSONDecoder()
            decoder.keyDecodingStrategy = .convertFromSnakeCase
            let result = try decoder.decode(Response.self, from: data)
            
            callback(.success(result))
        } catch {
            callback(.failure(error))
        }
    }.resume()
        
}

You can use tools such as Quicktype.io to create a model from a JSON. This is an example model from your provided JSON. You can play around with this tool, and also there is an option "Renders output in a Swift 5 compatible mode" since you are asking about parsing in Swift 5 programming language.

import Foundation

struct User: Codable {
    let status: String
    let data: DataClass
}

struct DataClass: Codable {
    let network: String
    let txs: [Tx]
}

struct Tx: Codable {
    let txid: String
    let fromGreenAddress: Bool
    let time, confirmations: Int
    let amountsReceived: [AmountsReceived]
    let senders: [String]
    let confidence: Int
    let propagatedByNodes: JSONNull?

    enum CodingKeys: String, CodingKey {
        case txid
        case fromGreenAddress = "from_green_address"
        case time, confirmations
        case amountsReceived = "amounts_received"
        case senders, confidence
        case propagatedByNodes = "propagated_by_nodes"
    }
}

struct AmountsReceived: Codable {
    let recipient, amount: String
}

class JSONNull: Codable, Hashable {

    public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool {
        return true
    }

    public var hashValue: Int {
        return 0
    }

    public init() {}

    public required init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if !container.decodeNil() {
            throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull"))
        }
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encodeNil()
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM