Home > Mobile >  Encoding string data back to JSON is giving an error
Encoding string data back to JSON is giving an error

Time:03-25

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

  • Related