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

Posted

技术标签:

【中文标题】用于解析平台 REST API (JSON) 并解码为结构的 Swift URLRequest【英文标题】:Swift URLRequest to Parse Platform REST API (JSON) & Decode into Struct 【发布时间】:2020-12-21 16:19:18 【问题描述】:

我正在尝试使用适用于 Parse 平台(服务器)的可用 ios SDK 中不可用的特定功能,但我知道这些功能可用于 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

成功返回数据:

“结果”: [ "__type": "日期", “iso”:“2020-08-29T07:00:00.000Z” , "__type": "日期", “iso”:“2020-08-29T07:09:00.000Z” ]

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

还有来自 Rested.app 的输出截图:

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

我正在尝试使用 Codable/Decodable 方法并匹配 JSON 属性名称,将下载的数据移动到一个新结构中以表示对象。到目前为止我的代码如下(也内联了一些 cmets)。 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()
            
        
    

控制台输出为:

解码错误:keyNotFound(CodingKeys(stringValue: "__type", intValue: 无),Swift.DecodingError.Context(codingPath:[CodingKeys(stringValue: “结果”,intValue:无),_JSONKey(stringValue:“索引0”,intValue: 0)], debugDescription: "没有与键关联的值 CodingKeys(stringValue: "__type", intValue: nil) ("__type").", 底层错误:无))

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

【问题讨论】:

您的响应 JSON 中没有键 __type print("Decode Error: \(error)") => print("Decode Error: \(error)"); print("With response: \(String(data: data, encoding: .utf8))")可能会有帮助。 虚拟数据不会导致该错误,因此真实数据必须不同。 "--data-urlencode "distinct=TeeTime" 不是说要把&distinct=TeeTime 添加到URL 中吗?你没有在你的代码中这样做,不是吗?所以也许这就是响应不同的原因(以及为什么您可能希望将返回的数据显示为字符串)。 我的意思是?distinct=TeeTime,对不起,错字。检查 en.wikipedia.org/wiki/Query_string 和 developer.apple.com/documentation/foundation/urlqueryitem(以及相关的 *** 问题,如果需要)以使用您的参数构建它。 【参考方案1】:

@Larme 在 cmets 中为开场帖提供的答案。 @gcharita 的贡献是我的语法 应该 如果它与我正在执行的其他测试具有相同的结构(它不是 - 见下文)。

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

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

解码数据: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"] 代码。

【讨论】:

保留参数,使用URLQueryItems:***.com/questions/34060754/…

以上是关于用于解析平台 REST API (JSON) 并解码为结构的 Swift URLRequest的主要内容,如果未能解决你的问题,请参考以下文章

django rest api:JSON 解析错误 - 无法解码 JSON 对象

ReactJS:Rest API JSON 响应:如何解析

在C#中解析Json rest api响应[重复]

在 django rest api 中使用 POST 解析 Json 错误

PostgreSql 或 MongoDb 用于从 REST API 接收的 JSON 数据

BIRT 如何用 rest api 接口获取 json 做报表