API Fetch 返回 nil

Posted

技术标签:

【中文标题】API Fetch 返回 nil【英文标题】:API Fetch returns nil 【发布时间】:2021-12-27 03:29:42 【问题描述】:

fetch 没有抛出任何错误,它只是返回 nil,我不知道为什么,这是 api URL:

https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd&include_market_cap=true&include_24hr_vol=true&include_24hr_change=true&include_last_updated_at=true

注意:代币的数量是无限的,不仅仅是比特币,所以我无法对其进行硬编码。

看起来像:


    "bitcoin": 
        "usd": 51110,
        "usd_market_cap": 964544028181.903,
        "usd_24h_vol": 19080677597.123028,
        "usd_24h_change": 2.163373654971005,
        "last_updated_at": 1640575480
    ,
    thereCanBeMoreWhichIcan'tPredict: 
        ...
    

这是我创建的模型:

struct TokenSimplePriceCoingeckoUsdModel: Codable, Hashable 
    let usd, usd_market_cap, usd_24h_vol, usd_24h_change: Double?
    let last_updated_at: Int?

这就是我使用 Alamofire 获取它的方式:

func afRequest(url: URL) async throws -> Data 
    try await withUnsafeThrowingContinuation  continuation in
        // If another error try lowering the request error: (statusCode: 200..<300)
        // timeoutInterval is in seconds
        AF.request(url, method: .get, requestModifier:  $0.timeoutInterval = .infinity ).validate(statusCode: 200..<600).responseData  response in
            
            if let data = response.data 
                continuation.resume(returning: data)
                return
            
            
            if case let .failure(error) = response.result 
                print("???? Error on afRequest(): \(error)")
                continuation.resume(throwing: error)
                return
            
        
    


func getDataFromAPI(url: String) async -> Any 
    do 
        let url = URL(string: url)!
        let undecodedData = try await afRequest(url: url)
        let finalData = try JSONDecoder().decode(TokenSimplePriceCoingeckoUsdModel.self, from: undecodedData)
        
        return finalData
     catch(let error) 
        print("???? Error on getDataFromAPI(): ", error)
    
    return ""

当我打印我得到的回报时:

TokenSimplePriceCoingeckoUsdModel(usd: nil, usd_market_cap: nil, usd_24h_vol: nil, usd_24h_change: nil, last_updated_at: nil)

编辑:如果我这样做:

print(String(data: undecodedData, encoding: .utf8)!)let undecodedData ... 行下打印数据,因此确认问题出在使用我的模型解码时,我做错了什么?

【问题讨论】:

【参考方案1】:

我从未直接使用 alamofire 发出网络请求,但似乎错误在于您如何解码响应,假设 undecodedData 已经包含您想要的数据,您当前的响应模型不会解码“比特币”键,因此结构为零,您可以将结构更改为类似

struct BitcoinStats: Codable, Hashable 
    let bitcoin: TokenSimplePriceCoingeckoUsdModel


struct TokenSimplePriceCoingeckoUsdModel: Codable, Hashable 
    let usd, usd_market_cap, usd_24h_vol, usd_24h_change: Double?
    let last_updated_at: Int?

或者您可能想尝试直接解码“比特币”键的值,这样您就可以保持当前结构不变

更新: 因为 JSON 有“比特币”以外的其他键,所以这是我提出的动态解码数据而不需要硬编码键的解决方案: pastecode.io/s/tkim2jf0

【讨论】:

我不能像那样对令牌(比特币)进行硬编码,因为它会改变。为了简单起见,我只放了 1,但看看这个请求:https://api.coingecko.com/api/v3/simple/price?ids=tether%2Cwmatic%2Cethereum%2Cmoonriver&amp;vs_currencies=usd&amp;include_market_cap=true&amp;include_24hr_vol=true&amp;include_24hr_change=true&amp;include_last_updated_at=true 你可以看到它可以包含无限量 如果是这样,您可以尝试将它们解码为字典,我在这里添加了一个基于您的 JSON 的工作示例pastecode.io/s/tkim2jf0@Albert 嗨@Albert,请告诉我它是否适用于您的情况,如果没有,我们将尝试另一种方式 我现在正在测试它,它不起作用:/ 我试过这个:let data = try JSONDecoder().decode(Coin.self, from: undecodedData.data(using: .utf8)!) 我得到Cannot infer contextual base in reference to member 'utf8'Value of type 'Data' has no member 'data' 另外我如何将所有字符串分配给模型而不做额外的计算? 不,我使用的是 .data(使用:.utf8)!因为我的数据是字符串,在你的情况下你可以直接解码 JSONDecoder().decode(Coin.self, from: undecodedData)【参考方案2】:

您的值在bitcoin 对象内,因此您还需要对其进行解码。您可以从 quicktype.io 中的这个结构开始:

struct Prices: Decodable 
    let bitcoin: Bitcoin


// MARK: - Bitcoin
struct Bitcoin: Decodable 
    let usd: Int
    let usdMarketCap, usd24HVol, usd24HChange: Double
    let lastUpdatedAt: Int

    enum CodingKeys: String, CodingKey 
        case usd
        case usdMarketCap = "usd_market_cap"
        case usd24HVol = "usd_24h_vol"
        case usd24HChange = "usd_24h_change"
        case lastUpdatedAt = "last_updated_at"
    

然后你可以使用 Alamofire 5.5 新的async 方法来自动解码:

let response = await AF.request(url).serializingDecodable(Prices.self).response

【讨论】:

请阅读我为@sushitrash 留下的评论,我无法对比特币进行硬编码,因为有无限数量的硬币,我怎样才能使它更灵活? 除非这些键都被命名为bitcoin,否则它们无关紧要。 查看simple 端点的文档,无论如何这不是真的。 coingecko.com/en/api/documentation 如果我尝试它会说:keyNotFound(CodingKeys(stringValue: "bitcoin", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"bitcoin\", intValue: nil) (\"bitcoin\").", underlyingError: nil))

以上是关于API Fetch 返回 nil的主要内容,如果未能解决你的问题,请参考以下文章

Fetch -API 返回 HTML 而不是 JSON

使用 fetch() API 返回部分视图

为啥 Fetch API 调用不返回响应标头?

FETCH API 返回 [object Object]

Restkit 从 Foursquare API 返回 nil 响应

将 PHP 异常返回到 javascript FETCH API