I've removed jsonCallback ( and ) from the URL https://www.apple.com/support/systemstatus/data/developer/system_status_en_US.js using the below.
var dataString = String(data: data, encoding: .utf8)
dataString = dataString?.replacingOccurrences(of: "jsonCallback(", with: "")
dataString = dataString?.replacingOccurrences(of: ");", with: "")
let json = dataString?.data(using: .utf8)
let jsonData = try JSONEncoder().encode(json)
The error I'm getting back
typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found a string/data instead.", underlyingError: nil))
I can't find where the mismatch is happening at because when I look at dataString and piece it back together the JSON decoding model appears to match.
Here's the full code:
func fetchSystemStatus() async -> [SystemStatus] {
guard let url = URL(string: systemStatusURL) else {
return []
}
do {
let (data, response) = try await URLSession.shared.data(from: url)
// This is commented out data to try and gather developer system status
var dataString = String(data: data, encoding: .utf8)
dataString = dataString?.replacingOccurrences(of: "jsonCallback(", with: "")
dataString = dataString?.replacingOccurrences(of: ");", with: "")
let json = dataString?.data(using: .utf8)
let jsonData = try JSONEncoder().encode(json)
guard (response as? HTTPURLResponse)?.statusCode == 200 else {
print("\(#function) \(response)")
return []
}
let statusData = try JSONDecoder().decode(SystemStatus.self, from: jsonData)
return [statusData]
} catch {
print("\(#function) \(error)")
return []
}
}
Model:
// MARK: - SystemStatus
struct SystemStatus: Codable {
let services: [Service]
enum CodingKeys: String, CodingKey {
case services = "services"
}
}
// MARK: - Service
struct Service: Codable, Identifiable {
let id = UUID()
let redirectURL: String?
let events: [Event]
let serviceName: String
enum CodingKeys: String, CodingKey {
case redirectURL = "redirectUrl"
case events = "events"
case serviceName = "serviceName"
}
}
// MARK: - Event
struct Event: Codable {
let usersAffected: String
let epochStartDate: Int
let epochEndDate: Int
let messageID: String
let statusType: String
let datePosted: String
let startDate: String
let endDate: String
let affectedServices: [String]?
let eventStatus: String
let message: String
enum CodingKeys: String, CodingKey {
case usersAffected = "usersAffected"
case epochStartDate = "epochStartDate"
case epochEndDate = "epochEndDate"
case messageID = "messageId"
case statusType = "statusType"
case datePosted = "datePosted"
case startDate = "startDate"
case endDate = "endDate"
case affectedServices = "affectedServices"
case eventStatus = "eventStatus"
case message = "message"
}
}
CodePudding user response:
This should work:
let statusData = try JSONDecoder().decode(SystemStatus.self, from: Data(json!))
or
let statusData = try JSONDecoder().decode(SystemStatus.self, from: Data(dataString!.utf8))
What's your issue:
let jsonData = try JSONEncoder().encode(json)
But json here is Data, so if you call JSONEncoder on it, by default, it will use Base64, so it won't be like the JSON you expect.
But json already is correct.
CodePudding user response:
The problem is that you encode data of the string not the model here
let json = dataString!.data(using: .utf8)
let jsonData = try JSONEncoder().encode(json) // < here is the problem
so you get an invalid data that doesn't represent your json string , BTW you don't need to use JSONEncoder() to convert the json string to data you need to supply that data directly to JSONDecoder()
let statusData = try JSONDecoder().decode(SystemStatus.self, from: json!)
to get it to work
