用于解析平台 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 对象
在 django rest api 中使用 POST 解析 Json 错误