Reputation: 5250
I am currently getting the following error in my tests:
If I correctly understood the problem, then I need to convert my dictionary to decoder.
At the moment i have the next code:
static var validConfirmAuthorizationData: [String: Any] { return json("valid_confirm_authorization_data") }
Which has the following structure:
{
"data": {
"id": "1",
"success": true
}
}
And the response class itself which I use together with the decodable:
public struct SEConfirmAuthorizationResponse: Decodable {
public let id: String
public let success: Bool
enum CodingKeys: String, CodingKey {
case data
}
enum DataCodingKeys: String, CodingKey {
case id
case success
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let dataContainer = try container.nestedContainer(keyedBy: DataCodingKeys.self, forKey: .data)
id = try dataContainer.decode(String.self, forKey: .id)
success = try dataContainer.decode(Bool.self, forKey: .success)
}
}
Upvotes: 0
Views: 1492
Reputation: 5250
It turned out to solve the problem as follows.
First of all, I created SpecDecodableModel
:
public struct SpecDecodableModel<T: Decodable> {
static func create(from fixture: [String: Any]) -> T {
let decoder = JSONDecoder()
decoder.dateDecodingStrategyFormatters = [DateUtils.dateFormatter, DateUtils.ymdDateFormatter]
let fixtureData = Data(fixture.jsonString!.utf8)
return try! decoder.decode(T.self, from: fixtureData)
}
}
After that, I can convert my JSON
structures to the desired type.
And now returning to the original problem, I can fix it as follows:
let fixture = DataFixtures.validConfirmAuthorizationData
let response = SpecDecodableModel<SEConfirmAuthorizationResponse>.create(from: fixture)
Update:
public extension Dictionary {
var jsonString: String? {
if let data = try? JSONSerialization.data(withJSONObject: self, options: []),
let string = String(data: data, encoding: String.Encoding.utf8) {
return string
}
return nil
}
}
Upvotes: 0
Reputation: 7
public struct AuthorizationData: Codable {
public let id: String
public let success: Bool
init(id: String, success: Bool) {
self.id = id
self.success = success
}
enum CodingKeys: String, CodingKey {
case id
case success
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
success = try container.decode(Bool.self, forKey: .success)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(success, forKey: .success)
}
}
public struct SEConfirmAuthorizationResponse: Codable {
public let data: AuthorizationData
enum CodingKeys: String, CodingKey {
case data
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
data = try container.decode(AuthorizationData.self, forKey: .data)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(data, forKey: .data)
}
init(_ data: AuthorizationData) {
self.data = data
}
}
func authData() -> Data? {
let authorizationData = AuthorizationData(id: "1", success: true)
let response = SEConfirmAuthorizationResponse(authorizationData)
guard let prettyJsonData = try? JSONEncoder().encode(response) else {
return nil
}
if let jsonString = String(data: prettyJsonData, encoding: .utf8) {
print("jsonString", jsonString)
}
return prettyJsonData
}
func authResponse() {
if let data = authData() {
guard let response = try? JSONDecoder().decode(SEConfirmAuthorizationResponse.self, from: data) else {
return
}
print("response", response)
}
}
Upvotes: 0
Reputation: 2216
You have a couple options, you could create a codable struct with a variable named data. Data would have the type SEConfirmAuthorizationResponse. Then you would decode into the new struct.
You could decode into a dictionary like:
let decoded = JsonDecoder().decode([String: SEConfirmAuthorizationResponse].self, from: someData)
let response = decoded[“data”]
Or you could write a custom decoder which I usually try to avoid.
Upvotes: 1