0

My API is always returning an response like this:

{
 status: string,
 error: string,
 meta: {},
 data: ?? // can be anything, an array,  an object, bool
}

I wanted to do something like this

struct ApiResponseModel: Decodable {
  let status: String
  let error: String
  let data: Data
  let meta: Data
  
  enum CodingKeys: CodingKey {
    case status
    case error
    case data
    case meta
  }
  
  init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    
    self.status = try container.decode(String.self, forKey: .status)
    self.error = try container.decode(String.self, forKey: .error)
    self.data = try container.decode(Data.self, forKey: .data)
    self.meta = try container.decode(Data.self, forKey: .meta)
  }
}

and use it like this

let serializedBody = try! JSONSerialization.data(withJSONObject: [
    "email": email,
    "password": password
  ], options: [.sortedKeys, .prettyPrinted])
  
  let response = try await AsyncNetworkManager.makeRequest(
    endpoint: ApiDict.loginsV1,
    httpMethod: .post,
    data: serializedBody
  )
  
  let responseModelData = try JSONDecoder().decode(ApiResponseModel.self, from: response)
  
  return try JSONDecoder().decode(LoginModel.self, from: responseModelData.data)

but it gives me an error

typeMismatch(Foundation.Data, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil)], debugDescription: "Expected to decode Data but found a dictionary instead.", underlyingError: nil)) The data couldn’t be read because it isn’t in the correct format.
breq
  • 24,412
  • 26
  • 65
  • 106
  • 1
    Do you know what will be in `data`? I mean, according to your call, you'll know if it's be a Bool, Array, Dict, etc.? https://stackoverflow.com/questions/49529208/ios-generic-type-for-codable-property-in-swift ? – Larme Jun 12 '23 at 09:02
  • Possible duplicate: https://stackoverflow.com/q/68254792/5133585 – Sweeper Jun 12 '23 at 09:03

1 Answers1

0

Thanks @Larme iOS Generic type for codable property in Swift

struct ApiResponseModel<D: Codable>: Decodable {
  let status: String
  let error: String
  let data: D
//  let meta: Data
  
  enum CodingKeys: CodingKey {
    case status
    case error
    case data
    case meta
  }
  
  init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    
    self.status = try container.decode(String.self, forKey: .status)
    self.error = try container.decode(String.self, forKey: .error)
    self.data = try container.decode(D.self, forKey: .data)
//    self.meta = try container.decode(Data.self, forKey: .meta)
  }
}

and request:

  let serializedBody = try! JSONSerialization.data(withJSONObject: [
    "email": email,
    "password": password
  ], options: [.sortedKeys, .prettyPrinted])
  
  let response = try await AsyncNetworkManager.makeRequest(
    endpoint: ApiDict.loginsV1,
    httpMethod: .post,
    data: serializedBody
  )
  
  let responseModelData = try JSONDecoder().decode(ApiResponseModel<LoginModel>.self, from: response)
  
  return responseModelData.data
breq
  • 24,412
  • 26
  • 65
  • 106