[SOLVED] Encoding string data back to JSON is giving an error

Issue

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"
    }
}

Solution

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.

Answered By – Larme

Answer Checked By – Cary Denson (BugsFixing Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *