Swift URLRequest 解析平台 REST API (JSON) 并解码为结构

Swift URLRequest to Parse Platform REST API (JSON) & Decode into Struct

我正在尝试使用可用的 iOS SDK for Parse Platform(服务器)中不可用的特定功能,但我知道这些功能可用于 REST API。专门使用 DISTINCT 查询。

在我的开发计算机 (Rested.app) 上使用 Parse Dashboard 和 REST API 客户端应用程序,我已验证以下查询按预期完成:

curl -X GET \
-H "X-Parse-Application-Id: someAppID" \
-H "X-Parse-Master-Key: someKey" \
-G \
--data-urlencode "distinct=TeeTime" \
http://somehost:1337/parse/aggregate/CompEntry

成功returns数据:

{ "results": [ { "__type": "Date", "iso": "2020-08-29T07:00:00.000Z" }, { "__type": "Date", "iso": "2020-08-29T07:09:00.000Z" } ] }

原始数据来自,共有3行,其中2行共享相同的TeeTime:

以及 Rested.app 输出的屏幕截图:

现在我正在尝试将其转换为我的 Swift / iOS 项目。

我正在尝试将下载的数据移动到一个新结构中来表示对象,使用 Codable/Decodable 方法并匹配 JSON 属性 名称。到目前为止,我的代码如下(也内嵌了一些注释)。 Struct 定义出现在单独的 .swift 文件中,但只要在主要 ViewController 定义之外。

struct TeeTimeData: Codable {
    let results: [Results]
}

struct Results: Codable {
    let __type: String
    let iso: String // TODO: THIS SHOULD BE A DIFFERENT DATA TYPE - I HAVE PICKED HARDER DATA TYPE TO START WITH!
}

然后在主 ViewController 结构中:

class ViewController: UIViewController {

    @IBAction func buttonGetTeeTimes(_ sender: UIButton) {
        
        if let url = URL(string: "http://somehost:1337/parse/aggregate/CompEntry") {
            var request = URLRequest(url: url)
            request.addValue("someAppID", forHTTPHeaderField: "X-Parse-Application-Id")
            request.addValue("someKey", forHTTPHeaderField: "X-Parse-Master-Key")
            request.httpMethod = "GET"
            let params = ["distinct": "TeeTime"] // TODO: THIS VAR IS NOT ACTUALLY BEING TIED TO THE REQUEST EITHER - 2nd PROBLEM...
            
            let session = URLSession(configuration: .default)
            
            let requestTask = session.dataTask(with: request) { (data, response, error) in
                
                if error != nil {
                    print("API Error: \(error)")
                }
                
                if let dataUnwrap = data {
                    // TODO: MOVE THIS INTO NEW CLASS (DataModel, etc)
                    let decoder = JSONDecoder()
                    
                    do {
                        let decodedData = try decoder.decode(TeeTimeData.self, from: dataUnwrap)
                        
                        print(decodedData)
                        
                    } catch {
                        print("Decode Error: \(error)")
                    }
                    
                    
                }
            }
            
            requestTask.resume()
            
        }
    }
}

控制台输出为:

Decode Error: keyNotFound(CodingKeys(stringValue: "__type", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "results", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: "__type", intValue: nil) ("__type").", underlyingError: nil))

我的第一个猜测是 属性 定义开头的 2 个下划线“__type”?

@Larme 在开场评论中提供的答案 post。来自@gcharita 的贡献,如果我的语法 应该 与我正在执行的其他测试的结构相同(事实并非如此 - 见下文)。

发生错误是因为返回的结果是不同的 JSON 结构,因为未应用 distinct=TeeTime 过滤器。所以它返回一个 JSON 对象,其中包含来自 class 的所有数据行,而不是我的 TeeTimeData 结构对象中指定的那些。

?distinct=TeeTime 附加到 URL 字符串的末尾解决了该问题并且 returns:

Decoded data: TeeTimeData(results: [Parse_2.Results(__type: "Date", iso: "2020-08-29T07:00:00.000Z"), Parse_2.Results(__type: "Date", iso: "2020-08-29T07:09:00.000Z")])

这也意味着我不再需要 let params = ["distinct": "TeeTime"] 代码。